Strict 3-role orchestration for Claude Code sessions. Python hook engine with model enforcement, structured feature tracking via features.json, and Factory-grade anti-drift protection.
/enter-mission [task]— Enter Mission Mode (auto-resumes if interrupted)/exit-mission— Emergency stop — always works, bypasses all guards/mission-config— View/set model defaults for all 3 roles/mission-status— View mission progress with per-feature status fromfeatures.json
- Orchestrator — Plans, delegates, reviews. NEVER writes code. Creates and tracks
features.json. - Worker — Implements code as assigned per feature. NEVER plans, tests, or validates.
- Validator — Verifies per-feature, writes tests, generates structured reports. NEVER writes production code.
Roles are enforced at the tool-call level by three Python hooks sharing a common engine (hooks/engine.py):
hooks/phase-guard.py(PreToolUse) — Blocks forbidden tool calls per phase. Covers Write, Edit, MultiEdit, Agent, and Bash tools.hooks/mission-reminder.py(PreToolUse) — Injects role-specific anti-drift reminders before every tool call. Feature-aware fromfeatures.json.hooks/mission-continue.py(PostToolUse) — Injects continuation reminders after every tool call with strength gradient (STRONGEST for Agent, MEDIUM for Read/Write, LIGHT for Grep/Glob).hooks/mission-stop.py(Stop) — Blocks Droid from stopping while a mission is active. Prevents the model from ending its response mid-mission. Respectsstop_hook_activeto avoid infinite loops.hooks/mission-subagent-stop.py(SubagentStop) — Blocks Workers and Validators from stopping prematurely. Ensures structured handoffs/reports are produced before sub-agents return to the Orchestrator.hooks/mission-precompact.py(PreCompact) — Writes.mission/checkpoint.mdbefore context compaction with full recovery state (phase, round, task, feature progress, next action).hooks/mission-session-start.py(SessionStart) — Injects mission context on session start, resume, or post-compaction recovery viaadditionalContext. Enables automatic mission resumption.hooks/mission-prompt.py(UserPromptSubmit) — Injects brief mission context (phase, round, current feature) on every user message to maintain awareness.
All 8 hooks across 7 event types are registered in hooks/hooks.json and invoked via python3 directly. The shared engine.py module provides single-call state parsing, path canonicalization, model validation, and feature tracking — all using Python stdlib only.
Global config: ~/.mission/config.json
Per-project state: .mission/state.json
Feature tracking: .mission/features.json
Human-readable overview: .mission/mission-brief.md
active— Whether the mission is currently running.trueorfalse.phase— Current phase:"orchestrator","worker","validator", or"complete".task— The mission task description.round— Current validation round number.persistence— Stopping behavior:"relentless"(default, never stop until done),"standard"(respect limits),"cautious"(stop at first critical).progressBanners— Show progress banners at phase transitions. Default:true.strictPhaseLock— Enforce phase lock validation. Default:true.currentAction— What the Orchestrator is currently doing.features— Path tofeatures.json(structured tracking, replaces oldplan.md).models— Per-mission model overrides (takes precedence over global config).phaseLock— Object withphase,lockedAt,lockedBy. Ensures single-role execution.phaseHistory— Array of{phase, startedAt, endedAt}entries tracking phase transitions.issuesTrend— Array of{round, critical, high, medium, low, total}entries for trend analysis.
The Orchestrator creates .mission/features.json during initialization. This is the machine-tracked source of truth for all features:
{
"features": [
{
"id": "feature-slug",
"description": "What needs to be done",
"assignee": null,
"status": "pending",
"dependencies": [],
"handoff": null
}
]
}Status lifecycle: pending → in-progress → completed | failed
The Orchestrator dispatches Workers per feature, tracks handoffs in features.json, and uses feature statuses as the primary completion gate. All hooks read features.json for context injection.
Models for each role are configured via ~/.mission/config.json (or overridden per-mission in state.json):
models.orchestrator— default:"opus"models.worker— default:"opus"models.validator— default:"opus"
The phase-guard hook enforces models on Agent dispatch:
- Correct model → ALLOW
- Wrong model → BLOCK with expected model in message
- Missing model → Auto-inject correct model from config
Only mission agents (mission-worker, mission-validator) are checked. Non-mission agents bypass model enforcement.
The phase lock mechanism guarantees single-role execution:
- The Orchestrator writes
phaseLockto state.json before every phase transition. phase-guard.pyvalidates thatphaseLock.phasematches the currentphase.- If
strictPhaseLockis enabled and they don't match, the hook blocks the tool call. - Only the Orchestrator can modify
phaseLock(Workers and Validators are blocked from writing to state.json). - Valid transitions:
orchestrator→worker,orchestrator→validator,orchestrator→complete,worker→validator,validator→orchestrator.
Ten hook-enforced defense layers in hooks/phase-guard.py:
| # | Defense | What it blocks |
|---|---|---|
| 1 | Completion Guard | phase: "complete" without validator report. Relentless requires Verdict: PASS. |
| 2 | Cleanup Guard | active: false + completedAt without summary.md or with leftover worker-logs |
| 3 | Worker Test Block | Workers writing *.test.*, *.spec.*, *_test.*, tests/*, __tests__/* |
| 4 | Validator Path Lock | Validators writing to .mission/ except .mission/reports/* |
| 5 | Anti-Premature-Completion | Completion in relentless mode when report says FAIL |
| 6 | Model Enforcement | Wrong model on Agent dispatch; auto-injects if missing |
| 7 | Phase Lock | Tool calls when phase ≠ phaseLock.phase (if strictPhaseLock enabled) |
| 8 | Unknown Phase Block | All tool calls when phase is not in valid set |
| 9 | Stop Guard | Droid stopping while mission is active (non-complete phase) |
| 10 | SubagentStop Guard | Workers/Validators stopping without producing handoff/report |
/exit-mission bypasses all guards using endedAt instead of completedAt.
Two anti-drift hooks fire for ALL roles (orchestrator, worker, validator) on every matched tool call:
- PreToolUse (
mission-reminder.py) — Injects[MISSION SKILL ACTIVE — DO NOT DEVIATE]with role-specific directives and feature context fromfeatures.json. Includes compaction recovery state (phase, round, task, current feature, current action). - PostToolUse (
mission-continue.py) — Injects[MISSION ACTIVE]with strength gradient. STRONGEST reminder for Agent calls includes full recovery context sufficient to resume after 20+ tool calls or context compaction.
Both hooks read features.json and show only the current in-progress feature. Both handle missing/malformed state gracefully and never exit non-zero.
Three additional lifecycle hooks ensure continuity across session boundaries:
- Stop/SubagentStop — Block premature stopping for the main session and sub-agents, ensuring the mission loop completes.
- PreCompact — Saves a checkpoint file before context compaction so the model can resume from the exact point.
- SessionStart — Auto-injects mission context when a session starts or resumes, triggering the Resume Protocol.
- UserPromptSubmit — Keeps the model aware of the active mission on every user message.
The mission loop runs in a single response turn. The mission-continue.py PostToolUse hook fires after every tool call, reminding the model to continue. If interrupted, the Resume Protocol in SKILL.md auto-detects the active mission via state.json and features.json and resumes from the current phase.
The cleanup guard enforces this order:
- Generate
.mission/summary.md(includes per-feature summary fromfeatures.json) - Clean
.mission/worker-logs/*.md - Then and only then: set
active: false+completedAt - Output final summary to user (from memory, before deletion)
- Delete
.mission/directory entirely:rm -rf .mission/
Step 5 is safe because hooks exit early when active is not "true". The directory (including state.json, features.json, reports, and logs) is not preserved after completion.