Skip to main content
The reconcile gate is the safety mechanism that fires every time you pop a detour. A fresh-context review re-reads the paused epic’s proposal and diffs what the detour actually changed, then delivers a verdict — valid or invalidated — before a single new line of code gets written. This is PM’s answer to a real problem: the thing that got interrupted doesn’t get to just “remember” what was planned. It gets re-validated, the same discipline as saving and restoring context around a hardware interrupt.

Why it exists

A detour might ship changes that invalidate the design or task list of the paused epic. A bug fix might refactor the very interface your feature was building against. A shared-behavior change might make three of your queued tasks redundant — or contradictory. Resuming blindly means building on a stale plan. If the detour was substantial enough to push onto the stack (rather than handled as a minimal detour), it was substantial enough to potentially change what the paused epic needs to do. The gate catches this mechanically rather than relying on an agent to remember to check, or on a human to notice the drift before it compounds into a harder conflict later.

How it works

1

Resume triggers the gate

/pm:resume pops the top detour stack frame and checks whether reconcileOnResume was true. If yes, reconcileNeeded: true is set on the paused epic and the gate fires before any code can be written. As of 0.44.0 the obligation is also recorded per detour on the paused epic’s may-invalidate link (reconcileOnResume: true, written only by push-detour --reconcile), so pop-detour prints RECONCILE GATE naming EVERY detour still owed — including an earlier --reconcile detour a later --no-reconcile push did not cancel.
2

A fresh-context review is dispatched

A clean-context review is delegated via the Task tool with the paused epic id and the detour epic id. It runs with no prior conversation history — this is intentional, preventing any in-session assumptions from contaminating the review.
3

The review reads and diffs

The review reads the paused epic’s proposal (and tasks.md for openspec-lane epics), then diffs what the detour actually shipped. It returns a structured response:
  • VERDICT: valid or VERDICT: invalidated
  • AMENDMENTS: — one amendment per line (stories to add, remove, or change). Empty if valid.
4

The verdict is written back durably

The verdict is recorded via:
This attaches {verdict, amendments, reconciledAt} to the paused epic’s may-invalidate link to the detour in .conductor/state.json. The judgment survives past this conversation instead of only ever living in the transcript. As of 0.44.0 the verb never creates a link: the verdict is refused, with nothing written and the owed detours named, against the paused epic itself, an unrelated epic, a --no-reconcile detour, or a detour whose frame is still on the stack. reconcileNeeded clears only when no armed detour is left unanswered; re-recording against the same detour moves the earlier verdict to superseded. --amendments none records no amendments, each --amendment is kept verbatim (a ; inside stays inside), and the two flags together are refused.

Verdicts and outcomes

valid

The detour’s changes don’t affect the paused epic’s design or task list. The review says so explicitly. State is updated and you can resume building. No amendments needed.

invalidated

The detour shipped changes that conflict with or supersede part of the paused proposal. You must update the OpenSpec proposal and tasks.md (or the stories[] for a claude-code-lane epic) to reflect the amendments before writing new code.
Either way, the record-reconcile call is required — even for a valid verdict. It’s what actually clears reconcileNeeded and lifts the gate-guard block. Do not hand-clear reconcileNeeded directly in state.json.

The gate guard

The gate guard is a PreToolUse hook that mechanically blocks Edit, Write, and NotebookEdit — and, on a Bash call, a member of a closed, documented list of write shapes (0.46.0) — while the active epic has reconcileNeeded: true. It is:
  • On by default — no configuration required.
  • Unconditional — it fires regardless of the repo’s gateGuard setting. set-gate-guard off no longer bypasses this specific check; that flag is reserved for any future generalization of the hook mechanism.
  • The only path past it — run the reconcile gate and call record-reconcile. There is no override flag.
  • Not erasable by an ordinary verb (0.44.0) — clear-active, set-active <other> and archive-then-unarchive all leave the obligation owed (moving the active pointer off an owing epic warns), and update-epic <epic> --clear-links and remove-epic <detour> are refused while it stands. The render heal clears it only where nothing could ever answer it (no frame, no armed or pre-0.44.0 may-invalidate link), and says so on stderr.
  • Closed when state cannot be read (0.44.0) — while .conductor/state.json exists but cannot be read, the hook blocks Edit/Write/NotebookEdit and every Bash write shape too, because whether a reconcile is owed is then unknown — with a carve-out that an affirmed Bash call carrying a command is allowed whatever its shape, so the git remedies stay runnable; see /pm:gate-guard.
This means the gate guard is a genuine enforcement mechanism, not a reminder. An agent mid-task cannot accidentally start writing code on a stale plan because a hook blocks the write at the tool level before any edit reaches the filesystem.
The reconcile gate applies to all lanes whenever a detour is popped with reconcileOnResume: true. The OpenSpec two-gate review (Gate 1 / Gate 2) described below is a separate, additional mechanism specific to openspec-lane epics only.

OpenSpec two-gate review

For openspec-lane epics, PM enforces two separate gate reviews across the epic’s lifecycle — independent of the detour reconcile gate: Each gate is recorded with its own evidence — one form per gate, not one form for both (0.45.0 corrected every doc that taught otherwise; --gate 1|2 --verdict pass with no evidence exits 1, and a sha range on Gate 1 records the wrong kind of evidence):
This writes {verdict, reviewedAt, note?} onto epic.gateReview.gate1 or epic.gateReview.gate2 in state.json. Gate 2 is mechanically enforced: update-epic <id> --status archived rejects the transition for any openspec-lane epic that doesn’t already have a gateReview.gate2.verdict === "pass" recorded. Gate 1 is not itself required at archive time (it gates code, which already happened earlier), though recording it is good practice. As of 0.44.0 a Gate 2 verdict’s --base-sha/--head-sha are resolved when recorded and stored as full object names (a bound that is not a commit in this clone is refused), and the verdict is fresh only when its headSha reaches EVERY commit attributed to the epic — not only the last. See /pm:epic for the refusals. Non-openspec-lane epics (superpowers, claude-code, decision, external) are completely unaffected by the two-gate check. It never runs for them. An autonomous epic still requires record-gate-review to be called after each real gate review — narration alone in the conversation transcript does not satisfy the archive-time check, and there is no bypass flag.