Agentic Coding

Posts on AI-assisted and agent-based development.

Teach Your AI Agent to Ask Why

An AI agent recently handed me a fix that worked, passed its tests, and didn’t need to exist.

I was adding guest-created live challenges to Draft Chess. When a guest host opened their room’s settings and returned to the lobby, the challenge disappeared. Creating another failed with “You are already in a live game.”

The agent found solo rooms in setup, a status intended for rooms with two players. It wrote restoreSoloLiveSetupRooms to reset them on every lobby broadcast, then added a passing test for the helper. The test was correct. It tested the helper.

In review, I asked why opening settings should change the status at all. The agent checked the Ready handler and found that it never changes room status. The real cause was in the join flow: the returning host was being seated as a second player. Fixing that made the helper unnecessary, and we deleted it.

The agent found the cause in minutes once asked. What was missing from its process was the question: why was the room in the wrong state to begin with?

That is a symptom patch: code that makes the result look right while leaving the bug that made it wrong. The helper made lobby broadcasts responsible for cleaning up after a faulty join flow. When helpers such as restoreX or ensureValidY repair unexpected state, I want to know what produced it.

I keep running into code that doesn’t need to exist. In this case, the agent could find the cause, but its workflow let it skip that investigation. I addressed the gap with two additions: a short rule that asks the agent to explain proposed repairs, and a debugging skill that guides the investigation.

The rule: make the agent explain the repair

My repo already told the agent to prefer the smallest fix. But the helper added a new responsibility to every lobby broadcast: repair a state the join flow should never have created. I wanted the rule to distinguish a small diff from a fix that leaves less code to maintain.

The addition below asks the agent to establish why the repair is needed. Its trigger is the proposed code—an override, fallback, or corrector—so it can apply even when the task wasn’t labelled a bug fix.

## Before adding corrective code

When a change adds an override, filter, special case, retry, fallback, or
state-repair helper to correct a result that is already wrong:

- Identify the code path that produced the result and verify the
  explanation against that code. A plausible story is not a cause.
- Fix the faulty producer or the mistaken consumer assumption where it occurs.
- Keep a correction only for existing data, supported external input, or
  documented concurrency, and say why preventing the bad state is not enough.
- In the change summary, state the verified cause and justify any retained
  correction. If the cause is unknown, say so and stop for review before
  adding the corrector.

Repair-verb names (`restore*`, `normalize*`, `heal*`, `reconcile*`,
`ensure*`) on code that mutates domain state are a cue to run this check.

The last bullet makes uncertainty visible. It asks the agent to say when it cannot explain the bad state, giving me a decision to review before another helper becomes part of the application. Legitimate repairs still have a place; they need an explanation of the condition they handle.

I keep this check in project instructions that load automatically, so it is available before the agent chooses a fix. Depending on the agent to request it would recreate the original problem: it would have to notice the gap in its own reasoning.

If you already have instructions about minimal changes, add this section there. The full prefer-smallest-fix rule also covers scope and proportionate verification.

The skill: establish the cause before choosing the fix

The rule asks for an explanation. The skill supplies the investigation: reproduce the failure, establish its cause, and test the behavior the application should preserve.

---
name: debug-at-source
description: >
  Investigate bugs, wrong values, and unexpected state by reproducing
  the failure, tracing its cause, and verifying intended behavior.
---

# Debug at the source

1. **Capture the failure.** Record the triggering action or input, actual
   result, and intended behavior. Reproduce it where possible; state any
   limitation.
2. **Trace the producing path.** Follow the relevant handler and calls to
   the code that produced the unexpected result. Stay on the failing path.
3. **Establish the cause.** Separate verified findings from assumptions.
   Check that the explanation accounts for the failure. If it remains
   uncertain, identify the missing evidence before proposing corrective code.
4. **Choose the fix.** Correct the producer or the consumer's false
   assumption. Retain correction only for supported boundary behavior or
   existing data, and explain why fixing the producer is insufficient.
5. **Verify the behavior.** Exercise the original failing path and assert
   the intended result. Add regression coverage proportionate to the risk.
6. **Remove obsolete repairs.** Keep any correction that still has documented
   work to do. Summarize the cause, supporting evidence, and verification
   actually performed.

The useful output is an explanation you can challenge and a test tied to the behavior you need. In Draft Chess, that behavior is simple: a returning host keeps one seat, the room remains waiting, and an opponent can still join. Those requirements give the regression test a purpose independent of the helper the agent happened to write.

The distinction matters. A passing helper test tells me that the helper works as specified. Testing the original failing path lets me assess whether the application’s behavior is correct.

The description names the work—investigating bugs—so the agent can select it from the task without first recognizing a flaw in its approach. Ask the agent to use the skill when starting bug work.

Keep the configuration small

It is easy to respond to every bad patch with another rule. Over time, the agent starts each task carrying a growing set of instructions, many irrelevant to the work in front of it.

Before adding a rule or skill, I ask the agent to estimate its effect on token use and context: how much text it adds, how often it loads, and what extra reading or investigation it requires. I use those estimates to compare options; actual usage and review effort tell me whether to keep it.

Before I accept a repair helper, I want three things: what produced the bad state, why correction is needed here, and evidence from the original failing path. If the agent cannot establish the first, that is the next thing to investigate—even if the helper already passes its tests.

Contact

Let’s talk about what you need. I offer flexible pricing for early-stage startups and longer-term projects.

Form validation failed.