Charlie KrugThe Build Log

← All posts

The bug is easy to plant. Guaranteeing exactly one is the hard part.

Bughunt is a daily puzzle for developers: one short function, one planted bug, click the line you think is wrong. The whole game rests on there being exactly one defensible answer.

Here is a function. Exactly one line is wrong. Which one?

function lastN(items, n) {
  const out = [];
  for (let i = items.length - n; i <= items.length; i++) {
    out.push(items[i]);
  }
  return out;
}

If you spotted the <= (it runs one index past the end and pushes an undefined), you just played one round of Bughunt. Read a short function, click the line you think is broken, get an instant red or green verdict and a plain-English reason. One puzzle a day, the same for everyone.

Wordle, but for the thing you actually do at work

Wordle proved a tiny daily ritual can hold a huge shared audience: one puzzle, one sitting, everyone comparing notes. Developers don't have that for the skill they practice for a living, which is reading code and noticing what's wrong with it. The existing options are a LeetCode-style grind (too much commitment for a habit) or a one-off blog post (no streak, nothing to come back for tomorrow).

Bughunt is that ritual, sized for 60 seconds. A new hand-crafted snippet each day, syntax-highlighted, with a single deliberately planted defect. Click the buggy line, keep your streak, share a spoiler-free result card. The bank ships with 32 puzzles across 7 languages (JavaScript, TypeScript, Python, Go, Rust, Java, C) and 8 bug categories: off-by-one, null-check, type-coercion, scoping, mutation, async, comparison, and boundary.

Click, don't type, so the feedback can be instant

The interaction is binary on purpose. There's no editor, no fix to write, no fuzzy "is this close enough" answer matching. Every line is a candidate and your whole input is which line. That single decision is what buys the sub-second verdict: the app doesn't have to interpret a patch, it just checks an index. The line you clicked flashes green or red, and a reveal panel tells you what the bug was and how to fix it. The entry bar is low (read a function, click once) but the skill ceiling is real, because off-by-ones and scoping traps are exactly the class of bug that survives a fast read.

Exactly one bug is the whole game

The mechanic sounds trivial to author, and it is the hardest part of the project. The bug is easy to plant. Guaranteeing there's exactly one defensible answer is not. Ambiguity is what kills a puzzle game: if two lines could each reasonably be called "the bug," every solve feels like a coin flip instead of a skill test, and the player stops trusting the verdict. So every puzzle is hand-written, not generated. Ask a model or a fuzzer to plant a bug on demand and you'll routinely get a snippet with a second, accidental defect a few lines up, or a "bug" that is really just a style choice. A planted bug has to be subtle enough to require real reading and unambiguous enough that one line, and only one line, is wrong. That only comes from careful authorship, one puzzle at a time.

The other quietly important decision: no server. The puzzle for a given UTC date is derived algorithmically from a fixed epoch and the bank, so the whole thing ships as a static site and yet everyone provably sees the same puzzle on the same day. Streak, mute, and onboarding state live in localStorage. No accounts, no backend, nothing to sign up for.

Because there's no server checking answers, the correctness has to be right at build time, so the logic is tested hard: 123 tests including property-based checks with fast-check over the daily-seed math, the attempt state machine, and the streak invariant, with every pure logic module at 100% line coverage. Honest limitation: 32 puzzles is a few weeks of dailies. Keeping Bughunt sharp is a content problem more than a code one, and that's the part that has to keep growing.

Try it

Open Bughunt and read today's function top to bottom before you touch anything. Resist scanning for the answer; read it the way you'd review a teammate's PR. Click the line that feels off. Get it and your streak extends and you can copy a share card that reports your score, never the bug. Miss and the line goes red so you can look again. If you'd rather read the seed picker than trust it, the code is on GitHub.

Bughunt is live. Free, in your browser, no signup.

This post is part of the build log: every app my automated factory ships gets written up here, honestly. Browse everything at apps.charliekrug.com. Comments are open below.

Comments

Loading comments…