Fetching latest headlines…
Wiring a "read this first" hook as "ask" (don't)
NORTH AMERICA
πŸ‡ΊπŸ‡Έ United Statesβ€’July 1, 2026

Wiring a "read this first" hook as "ask" (don't)

0 views0 likes0 comments
Originally published byDev.to

In retrospect, it was pretty obvious... sharing it anyway.

I'm currently working on a self-steering progressive disclosure system, and I wanted my agent to read a design doc before it touched the code that doc governs. Simple PreToolUse hook: match Edit/Write, check whether the doc was Read this session, and if not, stop the edit and tell the agent to read it first.

I returned permissionDecision: "ask". My reasoning at that time: "ask has an escape hatch. Approve and the call proceeds, so a bad condition can never wedge the agent - you can always wave it through."

That safety was the whole problem. The approval is an escape from the prerequisite, not a path through it. The edits went through without the doc reads.

Here is what ask actually does. It surfaces the tool call for approval. Approve it - or auto-approve it - and the action runs. The doc never gets read. ask is a checkpoint for a human, not a gate on the agent. Nothing about it makes the agent do the prerequisite step.

The fix was one field. Return deny:

// PreToolUse hook, matcher: Edit|Write
if (!wasReadThisSession(governingDoc)) {
  return {
     hookSpecificOutput: {
         hookEventName: "PreToolUse",
         permissionDecision: "deny",
         permissionDecisionReason: `Read ${governingDoc} before editing this, then retry.`
     }
  };
}

deny refuses the tool call and hands the agent the reason. The agent can't proceed, so it does what the reason says - reads the file - and retries. The read clears the check, the retry passes.

This is the behavior Claude Code already ships natively: when it tries to Edit a file that haven't been Read before, the tool refuses the action until the relevant Read happens. The deny hook lets you apply that same read-before-edit rule to any file you designate, not only the file being edited.

The distinction I missed:

  • ask gates on approving the call.

  • deny gates on the agent doing the prerequisite work first.

If the goal is to force the agent's own behavior - read this, run that check, load that context - deny is the lever. ask just adds a human to the loop.

Important: this only works, if the gate releases accurately, when the prerequisite is actually done. A deny on a condition that never clears will wedge the agent. Mine keys off "was this file read this session," which the read itself flips.

Comments (0)

Sign in to join the discussion

Be the first to comment!