11 KiB
Ask, don't guess: clarification doctrine for the orchestrators
Date: 2026-09-16. Branch: feature/ask-dont-guess. Status: draft for user review.
Problem
The orchestrators (/ship-feature, /feat, /bugfix, /hotfix,
/init-project) settle choices the user never made. Reported symptom: "add a
share icon" ships with the icon wherever the executor put it; nobody asked
left or right.
Two causes, both written in the doctrine:
lib/contract-interview.mdSTEP 2 asks a question only when a testable outcome, a scope, or a non-contradictory constraint is missing. A request can pass all three and still leave every visible choice open. Taste is invisible to the trigger, so raising the 3-question cap would change nothing.- When an executor halts with
NEED-DECISION,skills/feat/SKILL.md:153andskills/bugfix/SKILL.md:165instruct the orchestrator to "make the decision HERE", twice, before escalating. The question reaches the user after two guesses.
The parent rule both inherit is CLAUDE.global.md:51: "One question upfront
if needed — don't interrupt mid-task."
Decisions taken with the user (2026-09-15/16)
- The global rule changes, for all work, skill or not.
/hotfixincluded. - Three classes of open choice trigger a question: VISIBLE (placement, label, wording, color, order, click behavior), PUBLIC NAME (command, flag, endpoint, env var, file the user reads), SCOPE (should X change too, X unnamed in the request). Class 4, internal technical choices with no observable effect, never triggers one.
- Questions are asked when they arise, mid-task included, batched when possible.
Design
1. Parent rule, CLAUDE.global.md
Line 51 becomes:
- Ask rather than guess. A choice visible in the result (placement,
wording, order, behavior), a name that becomes public (command, flag,
endpoint, file), or a scope the request does not settle → ask, even
mid-task. Batch what can be batched. Internal technical choices with
no observable effect stay yours.
*Exception: skill-mandated gates and checkpoints (orchestrator
validation gates, approval gates, darwin checkpoints) always fire.*
The exception line is kept as is.
The rule "Bug received → fix directly: check logs, find root cause, resolve
autonomously." gains "; a visible choice in the fix still gets asked" so the
two lines do not contradict each other. link.sh:20 symlinks this file to
~/.claude/CLAUDE.md; no other copy exists.
2. Shared trigger, lib/contract-interview.md STEP 2
STEP 2 is renamed CLARIFY and split into two passes. Pass A keeps the three existing gap checks and runs at contract time, against the request. Pass B is the open-choice sweep: defined here, run once per flow at the PLAN step (section 3), against the plan just written, because that is where a visible choice becomes concrete. Replacement text:
## STEP 2 — CLARIFY (ask, never guess)
Two passes, both in the main loop, both may talk to the human.
**Pass A — gaps.** Run here, against the request. Ask if one of these is
missing AND not derivable from the repo:
- a testable expected outcome
- an unambiguous scope (what is allowed to change)
- non-contradictory constraints
**Pass B — open choices.** Defined here, run ONCE at the flow's PLAN step
(see "Where pass B fires"), against the plan just written — that is
where choices become concrete. Enumerate every choice the run will
settle that the request leaves open; keep those in these classes:
1. VISIBLE — the user would see it in the result: placement, label,
wording, color, order, what a click does.
2. PUBLIC NAME — a name that outlives the run: command, flag, endpoint,
env var, a file the human will read.
3. SCOPE — "should X change too?", where the request does not name X.
NEVER ask class 4 — internal technical choices with no observable
effect (function decomposition, data shape, local naming, layout inside
an already-scoped zone). Those are delegated; asking them is the noise
that makes classes 1-3 ignorable. Never ask what the repo or the
request already answers — verify paths/APIs/behavior yourself first.
No question cap. Each pass asks what it finds, in ONE batch. A request
that leaves nothing open goes through silently. More than 5 open
choices in pass B = the request is under-specified: list them, say so,
stop — do not fire a questionnaire. "You decide" / "peu importe" is an
answer: record it as `A: delegated — <default taken>` and never re-ask.
Pass B answers land in the contract's CLARIFICATIONS marked
`[gated <YYYY-MM-DD>]` — the contract is already on disk by then.
Two new sections follow STEP 4 in the same file:
## MID-RUN CLARIFICATION (the channel executors halt into)
An executor cannot talk to the human. It halts with `NEED-DECISION`,
the exact question, the options it sees, and a `CLASS:` tag (visible |
public-name | scope | internal). `/hotfix`: the hotfixer keeps
`DONE | BLOCKED`; a BLOCKED carrying the tag follows the same routing
instead of escalating to `/bugfix`. The orchestrator re-reads the
class — the tag is a hint, not a verdict — then routes:
- visible / public-name / scope → ASK THE HUMAN, verbatim question and
options. Never decide these yourself, never spend a round-trip
guessing.
- internal → decide here, note the decision, re-dispatch. The only case
the orchestrator settles alone; max 2 such round-trips → escalate.
Every answer, human or orchestrator, appends to the contract's
CLARIFICATIONS marked `[gated <YYYY-MM-DD>]` — the same micro-gate as
scope enrichment — and to the plan handed to the FRESH re-dispatched
executor, which reads the decision from disk, never from a transcript.
## HOW TO ASK (LRN-102)
The harness reliably renders only the turn's FINAL text; text printed
before a tool call may be swallowed. So:
- up to 4 questions → one `AskUserQuestion` call; option descriptions
carry the context; print nothing the user needs before the call.
- more than 4, or a list handed back for re-specification → plain
text, end the turn.
The per-flow weight table row for hotfix changes from "Zero questions ever" to "Pass A silent autofill. Pass B runs at LOCATE against the 1-2 target files' visible effect; a typo fix asks nothing."
3. Where pass B fires, per flow
| Flow | Pass B runs at | Against |
|---|---|---|
| feat | STEP 1 PLAN, before 1b CHALLENGE | the PLAN checklist |
| bugfix | STEP 3 FIX PLAN | the FIX PLAN |
| hotfix | STEP 1 LOCATE | the 1-2 target files' visible effect |
| ship-feature | STEP 2 PLAN, after the brainstorm | the plan, minus what the brainstorm already settled (in CLARIFICATIONS) |
| init-project | STEP 3 DESIGN, before VALIDATION GATE #1 | the DESIGN, minus what the interview and brainstorm settled |
| onboard | unchanged | its STEP 3 interview already asks scope in one block; the global rule covers leftovers |
Each listed step gains one line: "Run pass B of
$HOME/.claude/lib/contract-interview.md against this plan; ask the batch
before continuing."
4. Per-flow edits
skills/feat/SKILL.md: STEP 1's "If the approach is ambiguous: ask the user ONE focused question BEFORE dispatching — never after (the executor cannot relay questions)" is replaced by the pass B line. STEP 3'sNEED-DECISIONhandling is replaced by a pointer to MID-RUN CLARIFICATION. STEP 1b's "surfacing any deferred BLOCKER via STEP 1's one-question gate" is repointed to the pass B batch.skills/bugfix/SKILL.md: STEP 3 gains the pass B line; STEP 5'sNEED-DECISIONhandling is replaced by the pointer. The RULES line "re-dispatched FRESH on every round-trip (NEED-DECISION, …)" stays true.skills/hotfix/SKILL.md: STEP 1 gains the pass B line. STEP 1.7's "zero questions ever" becomes "pass A silent autofill; pass B was asked at STEP 1". The hotfixer keepsDONE | BLOCKEDand its revert-not-loop identity; STEP 4 relays a tagged BLOCKED as a question instead of escalating to/bugfix.skills/ship-feature/SKILL.md: STEP 2 PLAN gains the pass B line.skills/init-project/SKILL.md: line 62's "No new questions (the interview already asked)" becomes "Pass A is covered by the interview; pass B runs at STEP 3 against the DESIGN". STEP 3 gains the pass B line.agents/interviewer.md: the FAILURE MODES rows and the 2-round budget keep working for gaps. A class 1-3 item still open after round 2 gets ONE more targeted question; it never lands in OPEN DECISIONS as(assumed). The DO NOT entry "Exceed the 2-round budget" gains "except the one targeted class 1-3 question".agents/feater.md,agents/bugfixer.md: the halt trigger "A plan hole or an open choice (naming, data shape, API surface, dependency)" gains "a user-visible choice (placement, wording, behavior)". The NOTES grammar forNEED-DECISIONgainsCLASS: visible | public-name | scope | internal.agents/hotfixer.md: the NOTES grammar for BLOCKED gains the sameCLASS:tag when the blocker is an open choice.
5. Locks and tests
lib/tests/contract-verifier.test.sh: drop "silent when complete" "ZERO questions" and "question budget" "max 3 questions". Add locks on:
"goes through silently", "No question cap", "PUBLIC NAME", "NEVER ask class 4", "More than 5 open choices", "delegated —", "## MID-RUN CLARIFICATION", "CLASS:", "## HOW TO ASK".
lib/tests/loops-light.test.sh:84: "hotfix zero questions" "questions ever" becomes "hotfix pass B at locate" "pass B".
lib/tests/gates.test.sh locks on contract-interview.md (oracle doctrine)
are untouched; the ORACLES section does not move.
Behavioral check, run once by hand after the edits, in a fixture repo:
/feat "add a share icon to the header" must ask placement before
dispatching; /feat "add a share icon at the right end of the header, label Share, opens the native share sheet" must ask nothing.
6. Out of scope
README.md,USAGE.md,ARCHITECTURE.md: none mentions the question doctrine (grep 2026-09-16). A/docpass after merge covers any flow description that drifts.CHANGELOG.mdentry and registries (a BDR superseding the "one question upfront" rule) happen at the CAPITALIZE step, not in this spec.- TODO.md line 199 (C2 self-contradiction audit of
CLAUDE.global.md) stays open; this spec fixes only the contradiction it exposes.
7. Risks
- Chattiness. Three classes, a mid-run channel, no cap. The class 4 exclusion and the over-5 guard are the two brakes. Watch in real use; LRN-047 records that a frequent ignored nag is itself a risk.
/hotfixidentity. Its value is speed and silence. Pass B at LOCATE adds one possible batch before touching anything. If it fires on most hotfixes, the class definitions are too wide, not the flow.- Executor mis-tagging. A class 4 tagged as visible offloads a decision to the user. The orchestrator re-reads the class; the tag is a hint.