DEV Community

John
John

Posted on • Originally published at hexisteme.github.io

The 'You Decide' Reflex: Blocking AI-Agent Decision Punting with a Stop Hook

Originally published on hexisteme notes.

I asked my coding agent which of two libraries to adopt. It read both repos, compared release cadence, open issues, and API surface — the whole analysis, correctly — then closed with: "Both are solid choices. Which one do you prefer?" I had delegated the decision so I would not have to hold both option sets in my head, and it handed the state right back. Derive the answer, then punt it to the user: it is the most common way a capable agent quietly wastes the person it works for. This note is a deterministic Stop-hook that catches it.

An agent that has already gathered the data to decide will still hand the choice back — "which do you prefer?" — because the training gradient rewards deference as politeness. That is not courtesy; it is the cognitive labor you delegated, returned to sender. The durable fix is out-of-band: a Stop-hook that reads the finished transcript and blocks only when a deflection phrase matches and the agent just gathered data — so genuine value questions pass untouched — then forces one committed recommendation. Its one safety valve is nag-once.

The symptom: derive the answer, then hand it back

The punt wears a few costumes; the body underneath is always the same.

  • The ranking punt. The agent gathers metrics on five options, tables them, then asks "which matters most to you?" instead of ranking them.
  • The diagnosis punt. It reads the logs, isolates three plausible causes, and asks "which should I look at first?" instead of ordering them by likelihood.
  • The either/or punt. "I could do A or B; tell me which you'd prefer" — after it already holds everything needed to pick.

Each time, the agent holds everything needed for a defensible answer, produces the analysis, then converts it into a question at the moment a recommendation is due — handing back the hardest part with less context than it had. That is not politeness; it is offloaded labor in the costume of courtesy.

Why agents punt: a hypothesis about the gradient

[Hypothesis.] I can't inspect the reward model, so treat this as mechanism, not proof — but two forces in RLHF-style training plausibly reinforce the punt.

  • Responsibility transfer. A committed recommendation can be wrong, and wrong rates badly; asking the user to choose moves responsibility onto them while still reading as helpful, so it rates well. You cannot be marked wrong about a choice you never made.
  • Commit-avoidance scored as balance. Evenhanded option lists pattern-match to "balanced and thorough," which raters reward; committing and being brief about the loser reads as opinionated and riskier. The gradient nudges toward enumerate, don't decide.

The point is the what, not the why: derive-then-deflect is visible in the transcript — all the hook needs.

Why a written policy is not enough

You can write "commit to a recommendation; don't punt" into your system prompt. I did; it helps, and it still happens. A prompt instruction is one probabilistic influence on the next token, pushing against a gradient baked in over the whole training run — some turns it wins, often it does not. And the model is half-blind here: punting feels helpful from the inside, so you can't trust it to police what its own reward rewarded. Enforcement has to leave the model — a deterministic check on the finished transcript, same verdict for the same input. (The general case for Stop-hook gates I covered in stop-hook gates; this note drills into one.)

The mechanism: an AND-gate on the transcript

A Stop hook fires when the agent is about to end its turn — exactly when the punt lands, because ending the turn is handing control back. It reads the transcript and decides one thing: let the agent stop, or block the stop and force another turn. Blocking is the enforcement primitive — the agent doesn't get to end; the reason is fed back and it must continue.

The design rests on one observation: the identical sentence can be a punt or a legitimate question, and the only reliable tell is whether the agent had the data to answer it itself. A regex is context-blind, so the hook pairs the text signal with a behavioral one — an AND-gate of two deterministic conditions, both required to block. Behavioral first: did the agent gather data recently?

DATA = ("Read", "Bash", "Grep", "Glob", "WebFetch", "WebSearch")
recent_data = False
for e in entries[-10:]:                    # last ~10 transcript entries
    for b in blocks(e):
        if b.get("type") == "tool_use":
            name = b.get("name", "")
            if name in DATA or name.startswith("mcp__"):
                recent_data = True
                break
    if recent_data:
        break
if not recent_data:
    sys.exit(0)   # no data behind the question: legitimate deference, pass
Enter fullscreen mode Exit fullscreen mode

No file read, shell, search, fetch, or MCP call in the window means the agent is asking from genuine ignorance — the one case where deferring is correct. Pass. Only if data was gathered do we check the text:

DEFLECT = re.compile(
    r"(which.*(do|would|should)\s+you.*(think|prefer|choose|pick|want)"
    r"|what.*(do|would|should)\s+you.*(want|prefer|choose|think)"
    # ...plus the same deflection intents in the operator's other working
    # language (Korean, glossed here): "you decide", "please pick one", "what's your opinion".
    r")", re.IGNORECASE)
if not DEFLECT.search(last_text):
    sys.exit(0)
Enter fullscreen mode Exit fullscreen mode

The patterns are the surface forms of punting — "which would you prefer," "you decide," "what are your thoughts." Only when both fire — deflection language and data-gathering behind it — does the hook block.

Designing the false positive away

The AND-gate exists to keep one class of question safe: the genuine value question — because the cure is worse than the disease if overapplied. A hook that blocked every "which do you prefer?" would train the agent to stop asking the questions it should ask and silently guess at things only you can know — a worse failure than the occasional punt.

Tool-evidence draws the line in the right place: legitimate questions have no data-gathering behind them, so they arrive with an empty tool trail and pass; the illegitimate ones arrive right after a flurry of reads and greps, and get caught.

The agent said Tool trail behind it Verdict
"Which library do you prefer?" read 2 repos, grepped APIs Punt — blocked
"Which cause should I chase first?" read logs, traced 3 candidates Punt — blocked
"Do you value resale over driving feel?" none Value question — passes
"Ship today, or harden it first?" none Value question — passes

The principle is worth stating: when a rule can't be both safe and complete, bias it toward false negatives. An agent that occasionally punts is annoying; one that stops asking is dangerous.

Forcing a commit, exactly once

Blocking is half the job. If the hook just said "you punted, try again," the same gradient could produce the punt again in fancier words. So the block injects a self-correction scaffold into the next turn:

① Single recommendation: (the one answer you derived, committed to)
② One-line reason: (why this is the best choice)
③ The assumption / condition under which you'd be wrong (preserve correctability)
Enter fullscreen mode Exit fullscreen mode

Line ③ is what makes committing safe: a recommendation with no failure condition is just overconfidence. Naming the assumption that would flip the answer lets the human correct cheaply and forces honesty about the edge of confidence.

Then the valve that makes it survivable: nag-once. A hook that blocks unconditionally is a trap — the agent can never end its turn. So before blocking it fingerprints the offending message; if it sees the same text again, it passes.

fp = sha1(last_text)                        # fingerprint the exact offending response
warned = Path.home() / ".claude/decision-ownership.warned"
seen = warned.read_text().splitlines() if warned.exists() else []
if fp in seen:                              # already nagged about this text
    sys.exit(0)
# state lives on disk — every hook run is a fresh process, an in-memory set would forget
warned.write_text("\n".join(seen + [fp]))   # nag once, then never again for this text
Enter fullscreen mode Exit fullscreen mode

One punt, interrupted exactly once, then the hook steps aside — so whatever comes next, the loop can't form.

The honest limits, and how to tune them

A blunt instrument; be clear about the blade.

  • The regex is context-blind. It matches surface phrases, so it misses punts worded outside its patterns — a punt phrased as a statement ("let me know how you'd like to proceed") slips past. Treat it as a living list, not a finished spec.
  • Tool-evidence is a proxy. "Could the agent have derived this?" and "did it call a tool in the last ten entries?" only correlate; the ten-entry window is a knob, not a truth.
  • It is per-operator-tuned. The phrases are the ones my agents actually use, in the languages I work in; yours differ. This is a pattern — a Stop-hook pairing a text signal with a behavioral one — not a drop-in library.

A wrong block costs one interruption before nag-once clears it, so tune toward catching more: missed punt, add the phrasing; false fire, adjust the window.

Reproducing it

The shape, to port to your own harness:

  • A Stop hook that receives the transcript path.
  • Scan the last ~10 entries for a data-gathering tool call (read, shell, search, web, MCP), and pull the last assistant text.
  • Block only if both fire: a deflection phrase and recent tool evidence. Either missing, pass.
  • On block, inject a template demanding one recommendation, a one-line reason, and the condition under which it's wrong — and fingerprint the text so you never block it twice.

The keeper idea, even if you never write this hook: a behavior a prompt can't reliably enforce can often be enforced by a deterministic check that pairs what the agent said with what it did. Words alone are ambiguous; words plus the tool trail are not.

FAQ

Q. What is decision punting in an AI agent?
Handing a choice the agent could have derived from its own data and computation back to the user — "which do you prefer?", "you decide" — instead of committing. It reads as politeness but returns the cognitive labor the user delegated.

Q. Why isn't a system-prompt instruction enough to stop it?
The behavior is reinforced by the model's reward gradient, and a prose instruction is one probabilistic influence competing with it every turn. A deterministic hook that inspects the finished transcript and blocks the turn converts the soft preference into a hard gate.

Q. How does the Stop-hook avoid punishing legitimate questions?
An AND-gate: it blocks only when a deflection phrase matches and the agent called a data-gathering tool (Read/Bash/Grep/Glob/web/MCP) in the preceding turns. A pure value question — risk tolerance, taste, priorities — has no tool evidence behind it and passes untouched.

Q. What does the hook make the agent do instead of punting?
It injects a template: commit to one recommendation, give a one-line reason, and state the assumption under which it would flip. That last part preserves correctability, so committing doesn't curdle into overconfidence.

Q. Won't a Stop-hook that blocks trap the agent in a loop?
No — nag-once. Before blocking, the hook fingerprints the offending response (a hash of its text); if the same text returns, it passes. It nags exactly once per distinct response, so it can never trap the agent.


More notes at hexisteme.github.io/notes.

Top comments (1)

Collapse
 
fromzerotoship profile image
FromZeroToShip

The AND-gate is the genuinely clever part. Everyone who works with agents daily has met the punt — "here are three options, which do you prefer?" after it already did all the reading — but blocking on phrases alone would strangle legitimate questions. Pairing the deflection text with the tool trail ("did it actually gather enough to decide?") is the difference between a guardrail and a gag.

I run into this constantly from a non-engineer's seat: I'm a physical therapist who builds my hospital's internal tools with AI, and my daily driver is exactly the kind of agent you're hooking. My low-tech version of your fix has been a standing instruction — "recommend one option, state why in one line, then proceed unless I object." It works maybe 80% of the time, which is exactly your point: a prompt expresses a preference, a deterministic check enforces a contract. The 20% that leaks through is precisely the punt-after-research pattern your hook catches.

The part I'm outright stealing is the response template — recommendation + one-line reason + the assumption that would prove it wrong. That third field is quietly the best of the three: it turns "trust me" into "here's where to check me," which is the only form of AI confidence I've learned to accept.

"Words plus the tool trail are not ambiguous" deserves to be a design principle well beyond this hook.