Repository navigation
Mission layer M9.9: the six fixed roles, their wiring and two gates - #74
Merged
Merged
Conversation
The six mission roles (ROADMAP §4.12) are personas with eval suites, model routes, hook matchers on Claude Code, Codex and OpenCode, and Codex/OpenCode agents from `aloop install`. plugin/mission/roles.json names the paths each role may write. gate-mission-scope (PreToolUse) is the role path guard: a mission role writes only its own dirs, never source, mission.json or another role's dir, never commits or runs a human's approval; a builder never writes docs/agents/mission/ or runs a writing mission command; the supervisor never hand-writes a role's artifact. gate-mission-artifact records what exists at a role's start and, at its stop, requires an artifact in its own paths that passes the core contract and its area's check, refuses a deleted artifact or a change to another role's, and records artifact.created|updated as provenance. Test: scripts/test/mission-roles.test.py (26 checks), 5 new OpenCode end-to-end checks; make test-hosts, conformance-free lints and claude plugin validate --strict pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
…on skill The roles test compared a resolved plugin path with an unresolved temp dir, so it failed on macOS (/var is a symlink to /private/var). The OpenCode skill list moves to one table that also names the mission skill (aloop-mission, from M9.12) and skips a skill the plugin does not ship yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
…ount; due never runs past a cap
- due exits 2 with BLOCK[mission-due] when the facts cannot be read, instead
of 1 ("not due"), and the cron line logs due as well as the host session.
- At STOP_BUDGET due starts no session: it records the stop once itself.
- The token cap counts cache writes (on Claude Code nearly all new input).
- Stray event lines, a null sprints list, string counts in the ledger, a
mistyped cap or cadence, an unreadable mission.json: SET_MISSION or the
next step, never a traceback (_events.read skips non-object lines).
- Dotted, routed and Bedrock (global., us-gov.) model ids are priced.
- Second-resolution stamps tie toward "after".
- Gap items renumbered M9.19, M9.20 (#74 takes M9.18); new M9.21 (fast mode
and web search are not in the ledger).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Aw6CiQcdpzdzZZXKf8WbUM
…ixes) Two adversarial reviews of the role path guards found commands the old splitter let through (timeout/env/nice wrappers, if/for bodies, comments with an apostrophe, line continuations, `python3 …/bin/mission approve`, `bash -c`, `$VAR` targets, `sed -Ei`, `>|`) and legitimate ones it refused (a rival run in a mktemp scratch dir, `sed -i -e`, `git branch --show-current`, `truncate -s 0`). gate-mission-scope now reads a command with _shellread.py (quotes, escapes, comments, heredocs, reserved words, subshells, $(…) read as commands) and resolves variables, $(pwd) and $(mktemp). A mission role no longer writes the event log or the gates' state. gate-mission-artifact: an OpenCode child's start record waits until its role is known (a role-less record excused every change); intents other than `source: mission` are no role's; a run of the owner that overlapped (open, or stopped since) excuses a change; a status-only change to another role's artifact counts unless the human approved it; a human's approval of a role's own file is not its write; a human event during a run is named in a note and gate.passed (M9.17 attributes it); no start record blocks; a stuck release closes the run; a pass re-baselines it; checks share one 540s deadline; intents are checked in process (no intent.normalized); bad gates.jsonl lines are skipped. M9.19 records what is left: overlapping runs that share a path, and writes made inside a program. Tests: mission-scope-bash.test.py (175 commands), mission-roles.test.py (29 checks), opencode-plugin.test.mjs (25). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
# Conflicts: # CHANGELOG.md # docs/ROADMAP.md # docs/TRACKING.md
Merged master (M9.2, M9.3, M9.6, M9.10) and took up the asks from its review: - no one hand-writes docs/agents/mission/ledger.jsonl (its own message), and gate-mission-artifact blocks a stop when the ledger changed during the run and no longer verifies (new problems only); - `mission baseline restore` joins the human verbs; `events authority` and an `events emit` with role human (or unknown) or a human decision's type are blocked for every dispatched agent; - a supervisor write under docs/agents/mission/ never arms the sprint lock. Test: mission-roles.test.py (31 checks; one runs each role through the real journeys, baseline, assess and evaluate areas and checks its stop passes), mission-scope-bash.test.py (196 rows, 21 new, 11 failing on the previous gate); make test-hosts, lints, conformance 78/78 and claude plugin validate --strict pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
A dispatched agent's `events decide … --role human` (or an unknown role) is blocked like a human `events emit`. Test: mission-scope-bash.test.py (198 rows, 2 new). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
Already blocked for every dispatched agent (tick is the loop's); the row keeps it so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
…ates to its areas - An area's check runs once per artifact with its id or subject (roles.json `area_checks`): `mission ethics check` needs `--subject`, so every Ethics Reviewer stop failed with exit 64. An ethics hard line (exit 2, state hard) is the reviewer's finding, a note, not a defect. - A status change an event of the run explains is not another role's write: a human's step, or the role's own command (M9.8's tick hands `baseline apply` to the State Assessor, which freezes the researcher's journeys; a hard line blocks the planner's goal). Anything else still blocks. - No dispatched agent hand-emits a mission-layer event (mission.*, artifact.*, the areas'). - ROADMAP: my gap rows move to M9.26 and M9.27 (master took M9.18/M9.19, #75 takes M9.20–25). Test: mission-roles.test.py (32 checks; the new one runs the real ethics, baseline apply and journeys retire), mission-scope-bash.test.py (202 rows); make ci and conformance 78/78 pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
…rgery paths PR #82 (M9.17) makes a mission grant need the human's own words: a prompt line the UserPromptSubmit hook captured. gate-mission-scope now denies the ways around that, for every agent and the supervisor: - a write (Write/Edit/patch or a Bash write) under <run data>/transcripts/, the captured prompts; - a Bash `transcripts prompt|record|snapshot|stop|stage-in`, the hooks' own commands; - where a mission is set, a host session started from a tool call (`claude -p`, `codex exec`, `opencode run`, or any prompt), since its prompt fires UserPromptSubmit too. A host's tools (`claude plugin validate`, `--version`, `opencode models`) stay allowed; no mission, no rule. Test: mission-scope-bash.test.py (220 rows; 13 of the 18 new ones fail on the previous gate), mission-roles.test.py (32 checks); make ci, conformance 78/78 and plugin validate --strict pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
Docs only: ROADMAP takes master's M9.8 and M9.20–M9.25 rows beside this track's M9.9, M9.26 and M9.27; TRACKING marks both M9.8 and M9.9 implemented. make ci (conformance 78/78) passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
adeelahmad
marked this pull request as ready for review
October 20, 2026 04:12
…eck gets its id A derived goal's check waits on its ethics review, which is the Ethics Reviewer's step: area_checks marks those blocks foreign, so the planner's stop notes them instead of blocking. Gap rows renumbered to M9.30/M9.31. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
…#86) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw6CiQcdpzdzZZXKf8WbUM
The role runs use the real research and judge commands: the Scout's report is written through the CLI, and research and judge checks get the artifact's id. Gap rows move to M9.40/M9.41 (M9.28-M9.35 are taken by open PRs); M9.42 records the shared research dir and judge runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
…87 M9.28-30, #74 M9.40-42, #86 M9.50+) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw6CiQcdpzdzZZXKf8WbUM
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw6CiQcdpzdzZZXKf8WbUM
The section B approvals now go through the human's captured words, as M9.17 requires. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw6CiQcdpzdzZZXKf8WbUM
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AiLhAWTRtwbgMCDQNJUbea
This was referenced Oct 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Adeel · project thread
Before: the mission layer (ROADMAP §4.12) had its core and areas but no roles. Nothing stopped a builder from writing an evaluation, a grader from editing source, or any agent from running the human's approval steps.
After: the six fixed roles from the spec ship as personas, each with an eval suite, a model route and hook matchers on Claude Code, Codex and OpenCode. The roles are the Market Researcher, Product Tester, State Assessor, Evaluator, Mission Planner and Ethics Reviewer. Two new gates enforce role separation outside the model:
gate-mission-scope(PreToolUse) is the role path guard.plugin/mission/roles.json). It never writes source,mission.json, another role's dir, a task worktree, the event log or the gates' state. It never commits and never runs a human's step.mission approveand an area'sapprove,confirm,consent,veto,restoreorrevoke. They also includetick --force,events authority, and anevents emitordecidewith rolehuman.docs/agents/mission/and runs only read-onlymissioncommands.transcriptscommand, or hand-emits a mission-layer event. Where a mission is set, no one starts a host session from a tool call._shellread.py). It handles quotes, comments, line continuations, heredocs, wrappers,bash -c,eval, interpreters, variables and$(mktemp).gate-mission-artifactrecords what exists when a role starts. At the role's stop it checks three things:check. The check runs once per artifact, with its id or subject (area_checksin roles.json).A status change is not counted against the role when an event of the run explains it: a human's step, or the role's own command (
baseline applyfreezing journeys, an ethics hard line blocking its goal). An ethics hard line is the reviewer's finding, not a defect, and a derived goal whose only blocks are its pending ethics review waits on the Ethics Reviewer, not the planner. A pass recordsartifact. 8000 created|updated(role, agent id, sha256) as provenance. A run with no start record is blocked.How:
plugin/bin/_mission_roles.pyclassifies paths against the repo's worktrees and diffs the start record. Role lists in_routes,install,gate-dispatch,selfcheck,budgetand the OpenCode plugin name the six roles. OpenCode records a role's start on its firstchat.message, once the agent is known. A mission write never arms the sprint lock.Calls I made (recorded in §4.12):
docs/agents/intents/, but only itssource: missionintents count as its work.gate.passed, not blocked: the gate cannot tell who ran it (M9.17).research new --role product-testerand a judge run record need per-artifact ownership; no role setsALOOP_JUDGE_CMD). M9.42 and the second review's Bash-reader findings come next in a follow-up PR.Evidence:
scripts/test/mission-roles.test.py: 32 checks. Two of them run each role through master's real research, judge, journeys, baseline (new, measure, apply), assess, evaluate, ethics and goal commands, and its stop passes.scripts/test/mission-scope-bash.test.py: 220 Bash commands with expected exits. They come from two adversarial reviews and the asks of the M9.2/M9.3, M9.8 and M9.17 threads. Each batch of new rows fails on the gate before it.opencode-plugin.test.mjs: 6 new end-to-end checks.make ci(conformance 78/78) andclaude plugin validate ./plugin --strictpass locally on the merge with master (Mission layer M9.6: GA4 telemetry (opt-in, informs goals, never a gate) #71, Mission layer M9.4 ethics and M9.7 principles #72, Mission layer M9.1 research and M9.5 judges #73, M9.8 mission loop (tick, due, cron, budget caps) and M9.12 /aloop:mission skill #75, Mission layer: journeys, baseline, assess and evaluate (M9.2, M9.3, M9.10) #77, Mission layer hardening: the records decide (second review of M9.0/M9.2/M9.3/M9.10) #78, Mission goals and the Aladdin handoff (M9.11) #79, targets: a later task may modify a symbol another task plans #81, M9.6 telemetry: consent from the ledger, journeys by record, live verify #83, Mission loop review fixes (M9.8): restore, unmeasurable and vetoed proposals, block keys #84, Mission loop takes its ethics facts from the ethics verdict (M9.23) #85).🤖 Generated with Claude Code
https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj