The feature task is building new functionality on top of the existing code, with the AI doing much of the typing. You plan and prompt, then review and test everything it writes.
Planning and prompting#
Do the thinking before the AI writes anything, then hand it small, specific pieces.
1. Restate the spec and clarify#
Say the feature back in your own words, then ask about anything ambiguous: input formats, edge cases, the output shape, and whether performance matters yet. Two minutes here prevents building the wrong thing for twenty.
2. Plan before you prompt#
Say these out loud, before touching the AI:
- The approach and data structures. For example: "BFS over the grid, with a queue holding position and keys collected."
- The complexity.
- Where it fits. Which file it goes in, which existing functions and helpers it reuses, and what the new function signatures look like.
This is the problem-solving signal. If the AI picks your approach, you lose it.
3. Break it into pieces#
Each piece should be small enough to review in about a minute and testable on its own. A typical order is:
- A helper or core data structure.
- The main logic.
- Wiring it into the existing code.
- Edge cases.
For each piece, decide whether to write it yourself or have the AI write it.
| Write it yourself (or specify it very tightly) | Delegate to the AI |
|---|---|
| The core insight, meaning the part that is the algorithm | Boilerplate, parsing, formatting |
| Tricky state updates and invariants | Standard data structures (a trie, union-find, a heap wrapper) |
| Anything you'd struggle to explain if the AI wrote it | Test scaffolding and extra test cases |
4. Write prompts as specs#
Use this template for each piece:
Context: <file / function / class this belongs to>
Task: <one specific piece>
Signature: <function name, params, return type>
Constraints: <invariants, complexity target, existing helpers to reuse>
Edge cases: <empty input, ties, duplicates, etc.>
Don't: <change other files / rename things / handle X yet>Here's the difference in practice:
- Weak: "Add the key-collecting feature to the maze solver."
- Strong: "In
solver.py, writeneighbors(state, grid) -> list[State].Stateis(row, col, keys: frozenset). A door cell 'A'–'Z' is passable only if the matching lowercase key is inkeys. Stepping on a key cell adds it tokeys. Reusein_boundsfromgrid.py. Don't modifybfsyet."
The strong one shows you've already solved the problem and you're only delegating the typing. The interviewer reads that in the chat.
5. Keep the pipeline moving#
While the AI is generating, talk through the next piece. That keeps you from sitting in silence.
"While that's generating, the next step is plugging
neighborsinto the BFS and changing the visited set to track keys too."
Reviewing and testing what the AI writes#
Nothing the AI produces goes in unread or untested.
1. Read it before you accept it#
Treat every AI output like a coworker's PR.
| Check | What to look for |
|---|---|
| Matches what you asked | Same signature and return type, no silent renames, no extra parameters, no changed assumptions |
| Uses the existing code correctly | Calls the real helpers, respects the data models, uses the same index base and units |
| Edge cases | Handles every case you listed in the prompt |
| State | Mutation, aliasing, mutable default arguments, state shared across calls, caches over mutable data |
| Complexity | Meets your target. Watch for hidden O(n) work inside loops: x in list, slicing, string concatenation, sorting inside a loop |
| Invented APIs | Methods or library calls that don't exist, or don't behave the way the code assumes |
| Scope | Changes to things you didn't ask it to touch |
2. Decide: accept, fix, or reject, and say why#
Match your response to how wrong the output is.
- Small issue: fix it by hand. That's faster than re-prompting, and it shows you own the code.
- Wrong structure: re-prompt with specific feedback, like "Use a set for visited, and track keys as part of the state."
- Wrong twice in a row: stop prompting. Write it yourself, or switch models, and tell the interviewer why: "It keeps missing the door constraint, so I'll write this part myself."
3. Test after every piece#
Run the tests after each piece, not after three. Add one targeted test per piece, including at least one edge case. If something breaks, you know exactly which piece caused it.
4. Integrate and recheck#
After wiring the feature into the existing code, run the full suite. Make sure your bug fix still holds and nothing else broke.
5. Keep the optimization in mind#
Keep the core logic in its own function, so you can swap in a faster algorithm later without rewriting everything around it.
Narration#
Narration sounds like:
"It used a list for visited, which makes every membership check O(n). Switching to a set."
"It returns None for empty input, but the spec says an empty list. Fixing that by hand."
"This part looks right. Running the tests before I build on it."