team

Team Architecture

A deep dive into how Team is built. Skim it for the mental model, or read it in full to contribute. The high-level pipeline overview lives on the home page.

Source of truth: the artifacts in docs/plans/<id>/*.md and the in-session TodoWrite ledger.

Contents

1. Design philosophy

Agents are decoupled microservices. Each agent consumes a predecessor artifact on disk, does work, and produces its own artifact under docs/plans/<id>/. The orchestrator is the main session: it walks a linear phase table, dispatches the right specialist for each phase, seeds and updates a TodoWrite ledger, and runs the gates.

Principles:

Trust boundary. The single human checkpoint, the end-of-run PR review, is a code checkpoint, and it happens after the run has already executed. Local Bash execution (implementer, verifier, hooks), branch creation, pushes to remotes, and any multi-repo worktree effects all occur before a human sees the PR. The PR review contains the diff, the design’s recorded assumptions, and the deferred ## Review notes. It does not contain the run’s local side effects. The pipeline also assumes that repository content the researcher reads is trusted: a repo that accepts untrusted contributions feeds untrusted text into agent context. Merging remains human-only: nothing in the pipeline marks a PR ready for review or merges it.

2. Artifact layout & frontmatter

Runtime canon: the schema below is carried for agents by artifact schema. This section is the doc-surface copy. The executable ID_RE / PHASE_FILES definitions live in hooks/session-start-recover.mjs.

All phase artifacts live in docs/plans/<id>/, where <id> is one of:

Every artifact opens with YAML frontmatter. Common fields:

---
topic: <kebab-case>
date: 2026-04-30
phase: design        # task | questions | prd | repos | research | design | structure | plan
---

Per-phase additions:

Phase Extra frontmatter
task ticketId: <id> (or null)
questions (none)
prd (none. Not gated. The questioner writes it conditionally.)
repos (none. Written conditionally in multi-repo mode.)
research (none)
design revision: 0
structure (none. Not gated. It advances to PLAN once it exists.)
plan (none. Derived mechanically from the structure.)

Design-review record (design-review-<n>.md): each review round the orchestrator writes docs/plans/<id>/design-review-<n>.md (<n> 1-based per round) with frontmatter topic, date, phase: design-review, and verdict: <APPROVE|REQUEST CHANGES|COMMENT>. The body carries the reviewer’s findings verbatim. The verdict field is the deterministic read for hooks and resume detection. A design has passed review when the highest-<n> file carries APPROVE or COMMENT.

Review loop (REQUEST CHANGES): the design-author re-drafts with the reviewer’s findings verbatim. The orchestrator increments revision: <n+1> in the new draft’s frontmatter.

Phase inference (orchestrator + hooks):

Latest artifact present Current phase
worktree exists for <id>, no 1-task.md yet WORKTREE (next up)
1-task.md + 2-questions.md only RESEARCH (next up)
5-research.md DESIGN (next up)
6-design.md alone (no passing design review) DESIGN (review next)
6-design.md + passing design-review-<n>.md STRUCTURE (next up)
7-structure.md PLAN (next up)
8-plan.md + ≥1 commit on <id> since merge-base IMPLEMENT
8-plan.md (no commit on <id> yet) PLAN (next up)
topic branch has slice commits + verifier passed PR (next up)
PR opened or commit shipped SHIPPED

Worktree presence: git worktree list --porcelain | grep -q <id>. IMPLEMENT is confirmed only once there is ≥1 commit on <id> since merge-base with the default branch, so git log <merge-base>..<id> is non-empty. A present 8-plan.md with no commit means the run is still pre-IMPLEMENT.

Two non-phase sibling outputs exist. Discovery keys only on the six PHASE_FILES names, so both are invisible to hooks and skills, and IMPLEMENT still declares no phase artifact.

docs/plans/<id>/screenshots/ (PNGs plus manifest.md) is written by ux-reviewer during IMPLEMENT for UI-touching changes and consumed by team-pr. The upload itself, and every mechanic it needs, lives in skills/pr-screenshots/.

docs/plans/<id>/cross-model-notes.md is written by the orchestrator at the DESIGN review gate and the IMPLEMENT aggregate gate — one ### Cross-model disposition block appended per review round, at either gate, in which the cross-model pass ran — and consumed by team-pr for the PR’s ## Review notes section. It is created only on the first round that runs the pass, so a repo where the pass never runs gains no artifact. Beside it, docs/plans/<id>/cross-model-raw.md is the design path’s raw transcript — the orchestrator appends each vendor call’s result line and fenced output at capture time. Like the notes file, it is invisible to discovery: neither is a phase artifact, and neither is ever read back as state. Both frontmatter schemas (phase: cross-model-review and phase: cross-model-raw, no verdict) live in artifact schema.

3. Pipeline (QRSPI)

The pipeline has eight phases. The orchestrator walks them in order. Each phase needs the prior phase’s artifact on disk.

WORKTREE → QUESTION → RESEARCH → DESIGN → STRUCTURE → PLAN → IMPLEMENT → PR → SHIPPED

Phase 1: Worktree

Action: orchestrator-emit (the leading phase) Predecessor: none. The description arrives in ``.

Before QUESTION, the orchestrator creates the home worktree on branch <id> off origin/HEAD using Claude Code’s native worktree support, and authors docs/plans/<id>/ inside it. Because the artifact directory is born in the worktree, no copy is ever needed and the home checkout’s git status stays clean for the whole run. The orchestrator computes the worktree’s absolute path once and threads it into every downstream dispatch (the main session does not cd).

Single-repo (default): 4-repos.md is absent. One home worktree at <repo>/.claude/worktrees/<id>.

Multi-repo: the questioner writes 4-repos.md autonomously at QUESTION, one phase after WORKTREE. The design-author writes it at DESIGN when the questioner missed the multi-repo signals. Only the home worktree is created here. Secondary worktrees are created after the design review, one per listed repo. Each repo path must first pass the containment check: its realpath must be a direct child of the home repo’s parent directory.

git -C <repo-path> worktree add .claude/worktrees/<id> -b <id> origin/HEAD

At that point the orchestrator writes a ## Worktrees section to 4-repos.md. It back-records the home worktree path plus each secondary path. Any later /team-* invocation can thus rediscover all paths from one file. Only the home repo’s worktree carries docs/plans/<id>/. Other repos’ worktrees do not duplicate the artifacts. See skills/team-worktree/playbooks/worktree.md for full topology.

Fallback: if home-worktree creation fails (shallow clone, certain CI systems, permissions), the orchestrator reports it and falls back to in-place for the entire run: docs/plans/<id>/ lives at the home-repo root and the threaded path is the home-repo root.

Phase 2: Question

Agent: questioner Predecessor: worktree prepared (+ description in $ARGUMENTS) Artifacts: docs/plans/<id>/{task,questions}.md

Decomposes the user’s intent into two artifacts. Only the questioner ever sees the user’s description. There is no separate brief.md. Neutral codebase context lives in a “Codebase context” section at the top of 2-questions.md.

Phase 3: Research

Agents: file-finder and researcher (parallel, isolated) Predecessor: 2-questions.md (orchestrator passes only the 2-questions.md path to the research agents) Artifact: docs/plans/<id>/5-research.md

Orchestrator waits for both agents to return, then writes the combined research artifact with the necessary frontmatter.

Phase 4: Design

Agent: design-author (resolves its own open questions, recording each as an auditable assumption) Predecessor: 5-research.md Artifact: docs/plans/<id>/6-design.md Gate: REVIEW. The orchestrator dispatches a fresh-context, read-only Explore subagent with the ## Review brief from skills/eng-design-doc-review/references/design-reviewer.md. The subagent holds no Write or Edit tools, so the reviewer cannot touch the artifacts it judges. The orchestrator records the verdict to design-review-<n>.md. APPROVE and COMMENT advance. On REQUEST CHANGES the agent re-drafts with the findings verbatim and increments revision.

Phase 5: Structure

Agent: structure-planner Predecessor: 6-design.md + passing design-review-<n>.md Artifact: docs/plans/<id>/7-structure.md Gate: NONE (autonomous). Once 7-structure.md exists the pipeline advances to PLAN.

Phase 6: Plan

Agent: planner Predecessor: 7-structure.md Artifact: docs/plans/<id>/8-plan.md

No gate. The plan is mechanically derived from the structure.

Phase 7: Implement

Sub-pipeline:

  1. Test-first. test-architect writes failing acceptance tests.
  2. Mechanical gate. The orchestrator runs the suite and the project’s static checks. All tests must fail with assertion errors, not crashes, and every static check must pass — a runner that transpiles without type-checking leaves a red type checker behind a green suite. A change whose stated contract is zero behavior change inverts both steps: step 1 is skipped with a recorded reason, since the current suite is already the acceptance suite, and the gate becomes “the checks reproduce the baseline captured before any file moved”. Green is the correct state throughout.
  3. Slice execution. implementer works through the plan one slice at a time, committing each atomically.
  4. Code review. 5 reviewers in parallel: code-reviewer, security-reviewer, technical-writer, ux-reviewer, verifier.
  5. Aggregate gate. The orchestrator sorts every finding into a severity tier: Blocking, Major, or Minor-and-below. See skills/code-review/references/findings.md. Each round in which the code-reviewer’s report carries a ### Cross-model disposition block, the orchestrator appends that block — altered only by the blockquote wrap (every line prefixed with >) — to docs/plans/<id>/cross-model-notes.md (see section 2). While any Blocking or Major finding remains, it dispatches the implementer to fix the typed failure class. It then re-runs all 5 reviewers automatically. It never consults the user. This is the no-consult rule. Once Blocking and Major are clean, any remaining Minor-and-below findings are recorded in the PR body’s ## Review notes for the human’s PR review.

The orchestrator tracks the round count by appending Review round <n+1> (<b> Blocking, <m> Major open) items to the TodoWrite ledger. The count is that round’s open Blocking and Major total, so an operator watching the ledger can tell a converging loop from a stuck one.

Recovery after an operator stop, a context-exhausted session, or a fail-closed halt: a human re-invokes the same /team-* command bare. Each command runs its own phase and names the next one to run. What the human can fix first differs by gate.

The design-review gate writes every round’s findings to design-review-<n>.md, so they are on disk to read before editing 6-design.md. The aggregate gate persists none of its findings. So /team-implement resumes at the reviewer-dispatch step, and the five reviewers re-derive the open set at the cost of one round. The aggregate round counter is session-scoped through TodoWrite and starts fresh on re-invocation. The design revision counter persists in 6-design.md frontmatter.

Phase 8: PR

Action: orchestrator-emit Predecessor: aggregate gate passed

Update an existing CHANGELOG.md (filter for user-facing commits since last release); if the root file is absent, leave it absent unless the user explicitly requested one. Push the branch and open a draft PR automatically with gh pr create --draft. The PR phase never waits for approval. Then surface the tracking ticket, if 1-task.md carries ticketId. When the branch impacts a UI, the PR body also gets a ## Screenshots section, populated by one delegated call to the pr-screenshots skill, which attaches the PNGs and rewrites the body. UI impact is decided from the full branch diff; when ux-reviewer produced no capture manifest (docs/plans/<id>/screenshots/, see the artifact-layout note in section 2), the PR phase captures per the ux-reviewer brief before rendering the section. When docs/plans/<id>/cross-model-notes.md exists, its body (frontmatter stripped) is copied into the PR’s ## Review notes section, replacing the final round’s inline disposition block so every round appears exactly once. The worktree stays in place after the PR opens. Teardown is deferred until the PR merges or the user asks, so the branch remains available for iteration. The final report points at the standalone /pr-watch-as-author utility for watching the PR once it is ready for review.

4. Agent roster

13 specialist agents, organized by phase:

Phase Agents
QUESTION questioner
RESEARCH file-finder, researcher (parallel)
DESIGN design-author
STRUCTURE structure-planner
PLAN planner
IMPLEMENT test-architect, implementer, code-reviewer, security-reviewer,
  technical-writer, ux-reviewer, verifier (last 5 parallel)

Each agent’s QRSPI phase is recorded in skills/team/registry.json. Agent frontmatter uses only Claude Code’s supported fields. The dev hook .claude/hooks/check-registry-sync.mjs validates that the inventory in registry.json and the files under agents/ agree by name.

Checks and balances

The roster splits into two roles with deliberately non-overlapping powers. Producers write artifacts and code. Reviewers cast verdicts. No agent holds both powers, and neither role can complete a review cycle alone.

Role Agents Tools permissionMode Power
Producer questioner, design-author, structure-planner, planner, test-architect, implementer include Write/Edit acceptEdits Changes the tree. Casts no verdict.
Reviewer code-reviewer, security-reviewer, technical-writer, ux-reviewer, verifier read-only plan Blocks the line. Changes nothing.

This is enforced by frontmatter, not by prompt text. A reviewer that could edit could fix the defect it found and then approve its own fix, which collapses the generator and the evaluator into one role. Read-only tool grants plus permissionMode: plan make that impossible at the harness layer.

One path steps outside that enforcement: the cross-model pass (skills/team/references/cross-model-review.md) shells out to external vendor CLIs — the code-reviewer on the code path, the orchestrator on the design path — and an external process is beyond the harness’s tool grants. On that path the reviewer invariant is trusted, not enforced: codex and agy run with their full-access flags in the repo cwd — unsandboxed, with the invoking user’s permissions — and with a vendor CLI installed, diff and design-document content leaves the machine. What bounds the path is the pinned argv the bundled script hardcodes, the per-vendor env allowlist, the machine-wide TEAM_DISABLE_CROSS_MODEL kill-switch that disables both paths when set, the untrusted-output rules on everything a vendor returns, and the post-pass git status check that reports any vendor write as a blocking finding.

researcher and file-finder are also read-only, for a different reason: research isolation (see Phase 3). Read-only does not by itself mean reviewer.

Three more balances bound the checks themselves:

Model tiering

The principle: complex work runs on opus. Bounded judgment runs on sonnet. Mechanical checks run on haiku. fable (Fable 5) is the tier above opus: an agent runs there on a demonstrated, concrete need opus cannot meet. The tier is empty.

Notes:

Effort tiering

Effort tracks the work the agent does, on its own four-rung ladder: low (mechanical), medium and high (judgment — the band spans both rungs), and xhigh (strategic artifact authors). The xhigh tier holds design-author and structure-planner, whose artifacts set the direction everything downstream inherits. The ladder runs alongside the model ladder rather than off it, so an agent on sonnet at high is inside the rule: questioner is the live case, doing judgment work in a bounded single pass. Methodology skills carry no effort. They inherit it from the loading agent.

User-facing skills use the same ladder. The full /team orchestrator runs at high because it maintains state and applies gates across all eight phases. Single-phase orchestrators stay at medium; their specialist agents perform the complex work. Mechanical worktree setup runs at low, while entry points that directly perform complex analysis or conflict resolution run at high.

5. Phase-table orchestrator

The orchestrator (the main session) drives /team by walking the phase table in skills/team/SKILL.md. Pseudocode:

setup:
  resolve $ARGUMENTS (issue URL → gh issue view; ticket → use as prefix).
  derive <id> = "<TICKET>-<topic>" or "<YYYY-MM-DD>-<topic>".
  create docs/plans/<id>/ if needed.
  seed TodoWrite ledger with one item per phase.
  on resume: scan docs/plans/<id>/, fast-forward the ledger.

loop:
  1. Inspect TodoWrite. If all phases completed → exit.
  2. Identify the in_progress phase. Look up agent(s) and predecessor
     artifact path(s) in the phase table.
  3. Make sure that predecessors exist on disk. For STRUCTURE that includes
     a `design-review-<n>.md` with a passing verdict. If one is missing, the
     run is desynced. Suggest the bare /team-* command again. Its three-tier
     discovery resolves docs/plans/<id>/ without an explicit arg.
  4. Dispatch the agent(s) — pass them the artifact directory
     `docs/plans/<id>/`.
  5. Write returned artifacts to docs/plans/<id>/<name>.md with the
     YAML frontmatter the agent specifies.
  6. Run the gate for this phase (HUMAN | MECHANICAL | ORCHESTRATOR-EMIT
     | AGGREGATE).
  7. Mark current TodoWrite item complete and the next one in_progress.
  8. Goto loop.

6. Skills

Skills live under skills/. There are two flavors:

Entry-point skills (slash commands)

Every entry-point skill carries an argument-hint field in its frontmatter (Claude Code skills frontmatter) that documents the expected $ARGUMENTS shape.

Each downstream skill (team-research and beyond) treats $ARGUMENTS as an artifact directory, typically the path printed by the previous phase’s completion message. For the 8 directory-consuming skills (team-research, team-design, team-structure, team-plan, team-worktree, team-implement, team-pr, eng-design-doc-review) the docs/plans/<id>/ argument is optional. Each skill resolves the directory through a three-tier chain: explicit $ARGUMENTS → newest-mtime convention discovery → AskUserQuestion. The middle tier filters by ID_RE and PHASE_FILES, ported from hooks/session-start-recover.mjs as a POSIX ERE translation, and by the skill’s necessary predecessor artifact. The orchestrator or entry-point skill calls AskUserQuestion itself, never a subagent. Subagents never pause for user input. Standalone modes still exist. A partial skill invoked with no resolvable directory, or with a free-form description, bootstraps the missing upstream artifacts inline rather than hard-error.

Shared discovery helper. The 8 directory-consuming skills invoke the bundled skills/team/discover-topic.sh helper with their predecessor filename. team-structure also passes --require-passing-review. Each skill resolves <team-skill-dir> to the absolute directory containing skills/team/SKILL.md, then runs the helper from the repository root. The helper reads no host-specific environment variable or relative import. It owns ID_RE, PHASE_FILES, macOS/Linux mtime lookup, explicit-path precedence, and empty-success output when no candidate matches. The optional review filter accepts only APPROVE or COMMENT from the highest-numbered design-review-<n>.md YAML frontmatter. Line 1 and a closing marker within 60 lines must both be ---; malformed or over-cap input fails closed.

Methodology skills (loaded by agents, not directly invoked)

Methodology skills carry no argument-hint. Agents load them through one of two mechanisms. The first is a skills: YAML block list in the agent’s frontmatter, one indented - <name> per line.

After the playbook-and-verification consolidation, no methodology skill remains registered: the last two (running-quality-checks and verifying-ux) moved into the verify playbook and the ux reviewer brief. The block form is the contract: three test parsers read it, and the one-line inline flow form parses to zero names, so it is an offender rather than a second shape. The second is an inline prose load instruction in the agent body. All methodology content is now an ordinary resource rather than a registered skill: it lives in ordinary references such as the code standards and writing standards, which consumers read by path before work.

Principles are the third flavor. A principle is a guarded command: it sets disable-model-invocation: true, so the model never applies it on its own, and it carries no argument-hint. It stays user-invocable through /, and a consuming procedure reads it through its installed path — the same citation form ordinary references use. The catalog files it under ## Principles, and a read of its SKILL.md is a Uses edge in the catalog just as a load is. principle-fix-root-causes is read by the bug-fix playbook; its agents/openai.yaml declares allow_implicit_invocation: false for Codex.

Two reference forms, and the form is the contract. Every skill-to-skill reference is one of two kinds, and each has its own encoding:

Kind Reads Encoded as
Load — the reader must go execute that skill Call the Skill tool with `<name>` bare name
Citation — a schema lookup, a “see also”, a rule restated nearby skills/<name>/SKILL.md path

The citation row splits. A reference to a skill’s own SKILL.md is also an edge in the docs/skills.md Uses/Used by graph — the consuming procedure reads the skill, so it uses it. A reference to any other file in that skill’s directory is a citation only and draws no edge, and so does a reference that only locates a skill’s install directory (for example, “the directory containing skills/team/SKILL.md”, read to run a script beside it).

The imperative phrasing on a load is what makes a model actually issue the tool call. “Load X”, “see X”, and “per X” all read as citations, and a model that treats a load as a citation proceeds on the summary in its own context instead of the skill’s actual content — a slice ships without the commit conventions applied, a review runs without its severity table, and nothing announces either.

A load carries no path. The bare name is what the Skill tool takes, and a path sitting beside it reintroduces the ambiguity the imperative exists to remove: it reads as a file to go open. Name resolution is what replaces the path’s rename-detection, and it is strictly stronger — it catches a rename and a typo, where a path assertion only ever confirmed a string was present. skills/git-commmit/SKILL.md passed the old check.

Shared principles use six ordinary documents under skills/team/principles/. Artifact and operational rules use scoped references, outside registration. Consumers explicitly read their installed paths before work; missing files stop the consuming operation with the resolved path. The dispatch contract supplies definition and resource paths for named, body-loaded, and standalone agents.

The load form applies only where the other skill is genuinely needed. A citation keeps its path and its ordinary wording: a schema lookup, a “see also”, and a pointer to a skill the frontmatter already preloaded. Turning one of those into a tool call would spend a call and a slice of context on content nobody asked for. A citation to a skill’s SKILL.md still draws a Uses edge — the procedure reads the skill — even though it is not a load.

The phrase is load-bearing as the encoding. Changing the convention means changing every reference that carries it, deliberately.

Because they are reference material rather than user actions, methodology skills set user-invocable: false in their frontmatter. This keeps them out of the / slash-command menu. They stay fully loadable by their two mechanisms above. Neither the skills: preload nor a by-path load is affected by the field, which governs only menu visibility. Setting disable-model-invocation is a separate per-skill call with its own recorded reason, and no methodology skill has one: the model auto-loading a methodology skill when relevant is how it reaches one at all. When you add a new methodology skill, set user-invocable: false. When you add a new entry-point skill, leave it unset, so it registers as a slash command.

The field is honored by Claude Code only. Codex reads no invocability field at all, so it lists every registered methodology skill in its $ picker and a user can invoke any of them. Principles avoid that leak with disable-model-invocation: true plus allow_implicit_invocation: false in their agents/openai.yaml, which keeps them out of Codex’s implicit catalog. There is no fix on Team’s side, and the workarounds that look plausible all fail — see cross-host-portability.md before spending time on it.

The consolidated writing standards carry the former unslop and writing-prose content as one ordinary reference. Its Team-authored categories separate AI-pattern detection from sentence mechanics within one file.

The author scans the untouched draft with the exact-text and semantic guard before applying style edits. Exact source text stays byte-identical. The semantic guard protects normative force, permission, real uncertainty, and meaningful time relations. It outranks style substitutions.

Every agent and entry point reads the writing standards before finalizing prose. Agents audit only text they author. Orchestrators store and relay completed agent and vendor reports unchanged. The fresh design reviewer can use Read, Grep, Glob, and Skill, but no mutating tool. The technical writer uses the semantic guard to veto a readability finding that would change meaning.

Claude Code may retain the writing standards for later utilities in the same context before compaction. Compaction can evict that retained content. A recovered pipeline phase uses its phase entry and reloads the writing standards explicitly.

The trigger-phrase convention keys on the user-invocable field — not on argument-hint, which docs/skills.md uses to sort skill flavor. A skill that does not set user-invocable: false must state, in its description, at least one double-quoted natural-language phrase (one that does not start with /) plus its own literal /<name>, normally as a final Trigger on "…", "…", or "/<name>". sentence. A side-effecting or irreversible entry-point skill MUST carry shipit-style explicit-intent guard wording (“Invoke ONLY on explicit … intent — … never infer …”) beside or instead of the plain carrier, and still state the quoted phrases and the slash name.

Which skills are in that class is a complement pair over every write an invocation authorizes, so it returns one answer per skill. Out of class: the invocation reads only, or writes only (1) files under docs/plans/ and (2) invocation-local scratch files — untracked, created and consumed inside the same run, carried by no commit, and read by no later phase. In class: everything else — a change to any file the repo tracks, or to an untracked file the change is meant to deliver; a git write to history or refs (a commit, a branch, a rebase, a push, a branch delete); or a change on a host outside the checkout (a PR opened, approved, or merged; a ticket or issue moved, filed, or closed; a deploy). The verb list this replaced — commits, pushes, opens a PR, moves a ticket, merges, deploys, or deletes — still reads as an illustration of the in-class half. A write the invocation never authorized, such as an unsandboxed vendor CLI mutating the tree during a cross-model pass, moves no skill into the class: the caller detects that write and reverts it rather than authoring it.

Second tier: a skill that gates every mutation on its own in-run approval carries the guard there instead, which is where human-control rules puts it. groom-backlog is the worked example — it presents each irreversible close and waits. Setting disable-model-invocation is a further per-skill call with its own recorded reason, never a property of this class. An in-class skill stays listed as a command, and its routing-map line in AGENTS.md states the explicit intent, so the map never invites it on a plain request. The guard wording is the author’s and reviewer’s responsibility, and its absence on a side-effecting skill is a review-blocking defect.

No methodology skill is user-invocable. When a methodology also wants a user-facing command, the answer is a front door, not an exception: the methodology keeps user-invocable: false and a separate entry-point skill carries the slash command. The review procedures moved off the methodology list entirely: each reviewer brief is now an ordinary reference file owned by its entry point, so the front-door pair collapsed to one skill carrying a references/ file beside it.

code-review owns the code reviewer brief (skills/code-review/references/code-reviewer.md), the separate security and documentation briefs (security-reviewer.md, documentation-reviewer.md), and the shared finding format (findings.md). The code-reviewer, security-reviewer, ux-reviewer, and technical-writer agents read those briefs from the installed plugin; code-review carries argument-hint and effort like any other entry point and is catalogued under Standalone utilities. What stays on the front door is the one thing a user runs: “review this diff”. eng-design-doc-review owns the design reviewer brief (skills/eng-design-doc-review/references/design-reviewer.md), and team, team-design, and the front door all read it by path. no-comments owns the comment reviewer brief (skills/no-comments/references/reviewer.md): a read-only Explore reviewer classifies comments, then the invoking producer applies accepted findings and gates constraint encodings on approval.

A front door is a second kind of entry point, and both kinds are ordinary. One runs its own procedure; a front door owes the reviewer’s own rules and routes the work to whoever may do it. The main session shares conversation history with whatever wrote the code, so it is not a valid reviewer. code-review therefore dispatches the code-reviewer agent and relays the verdict rather than reviewing inline, then reads code-reviewer.md for the methodology that reviewer applies. eng-design-doc-review does the same with a read-only Explore subagent and the design-reviewer.md brief. no-comments uses that dispatch pattern but returns accepted findings to the invoking producer for edits.

(This is separate from the entry-point skills, which are user-invocable by definition. Some of those, e.g. team-worktree and team-pr, are also referenced by path from team/SKILL.md, but those are procedural cross-links in the orchestrator’s prose, not a parent loading the skill as a building block. The reviewer briefs are how a composed review keeps a user-facing entry point without becoming a methodology skill of its own.)

For the full per-skill reference (all skills, each with the skills it loads, which is the skill-to-skill dependency graph), see skills.md.

Design guidelines

Skill sources follow six rules: assert without arguing; state invariants instead of exhaustive case lists; define shared rules once; keep SKILL.md as a router to references/ and scripts; use descriptions only for capability and trigger; and test commands, numbers, names, paths, or behavior rather than prose wording.

Source budgets remain 80 lines for methodology and 150 for entry points. Descriptions are at most 200 characters, or 150 for methodology. An overage requires a reviewed reason stating its exact line count.

  1. Methodology skill load limit: three methodology skills is what an agent gets without argument. Every name in the agent’s skills: block counts, including the agent’s own procedure skill. An agent that lists more than three carries one recorded reason, and that record names the count it justifies. A fourth name still signals that the agent’s responsibility can be too broad, and answering that is what the reason is for.

  2. Extraction threshold: capability against fragment. Content that is an independently useful capability earns its own skill regardless of consumer count. Such content is coherent and self-contained, and the model or a future consumer can plausibly load it on demand. Claude Code preloads only each skill’s name and description. The body loads just-in-time when invoked. An unused small skill thus costs almost nothing. Content embedded into a consumer instead forecloses just-in-time loading for everyone else. Content that is only meaningful inside one consumer’s procedure, a procedure fragment, stays inline in that consumer.

  3. Shared principles: six ordinary documents define human control, durable state, verified results, independent review, focused work, and boil the ocean. Execution, external-data, decisions, and bug-fix resources own the remaining operational rules. Question, Research, Design, Structure, Plan, and Implement procedures live in playbooks with shared templates and dependency, testing, and diagnosis references. Code policy lives in the code-standards reference; prose policy lives in the writing-standards reference. Read only applicable resources from the installed skill or agent base. Stop missing reads with the exact path. Twelve agent bodies read execution rules. File-finder retains its single-step contract. Resources use no skill frontmatter or discovery metadata. Keep the 27 commands registered. Guarded principles are their own tier: they carry skill frontmatter and agents/openai.yaml, register as commands, and set disable-model-invocation: true so the model never applies them on its own. Do not add unguarded principle registrations, recursive loading, compatibility stubs, or a resource registry.

Codex host manifests

Every skill under skills/ carries agents/openai.yaml, the per-skill manifest Codex reads to build its catalog entry. Without one, Codex falls back to the directory name and a truncated description:. The file is optional upstream and mandatory here.

Three fields, each derived from the skill’s own SKILL.md frontmatter rather than stored twice: display_name title-cases the kebab name: through two closed lists (acronyms up, joiners down); short_description is an imperative phrase in the spec’s 25-64 character window; default_prompt is Use $<name> to <short_description with its first character lowercased>., using the skill’s own declared name as the explicit-invocation token. No icons, no brand color. A policy block declaring allow_implicit_invocation: false appears if and only if the frontmatter sets disable-model-invocation: true, and the test asserts that equality in both directions.

short_description has no mechanical derivation. The creation guide requires updating agents/openai.yaml whenever description: changes; the manifest gate checks its shape and length.

OpenCode adapter

Distributed opencode/team.js exports only the native plugin function. It resolves its real checkout and imports opencode/catalog.mjs, the same catalog validator used by script/dev-opencode.mjs. The Bash lifecycle entry scripts require Node. script/dev-install/dev-uninstall and dev.yml route the OpenCode target to them. opencode/ counts as distributed runtime for land-time versioning.

The catalog enumerates immediate real skill directories in stable order, reads each header once, and walks each tree once without following links. It rejects nested skill files, symlinks, invalid/ambiguous consumed frontmatter, duplicate names, empty catalogs, and canonical template-marker paths. References and scripts remain canonical files. Install validates before registration; plugin initialization validates before returning config contributions. Existing command collisions and invalid consumed config types fail before any config mutation.

All skills receive native configured commands containing canonical file/base pointers and $ARGUMENTS, without embedded bodies, model overrides, or agent overrides. This includes methodology skills marked user-invocable: false. Frontmatter disable-model-invocation: true excludes only Team’s added native skill paths. Those skills still have explicit commands. Existing external skill sources may expose their own guarded copies or resolve duplicate names to other files. Team commands retain canonical pointers, but later plugins/MCP can collide.

Command-file reads use native read and external_directory permission. Unguarded cached skill loading uses skill permission. read: deny does not block that route. Supplied arguments retain native preprocessing, including shell syntax such as !`printf example` that can run before a model call, outside model-tool rules including bash: deny. File pointers preserve body text. They do not make arguments inert. See OpenCode support for usage and resolved-skill versus command-template diagnostics.

Lifecycle operations canonicalize the existing plugin parent, acquire its atomic team.js.lock directory, then inspect/change only the exact-owned symlink. They release only their acquired empty lock, refuse busy/stale locks, preserve config and credentials without reading them, and never invoke OpenCode. Install success means registered. Native config loading remains separate. New host processes read live checkout edits. Concurrent checkout edits or external replacement without the lifecycle lock are unsupported.

This adapter establishes discovery and lifecycle support. Full QRSPI execution, specialist/nested dispatch, reviewer isolation, and hook host-firing on OpenCode remain unverified; the hook adapter programs were probed by direct invocation (program contract verified, host-firing unverified — see hooks-portability.md). /retro stays guarded and discoverable and resolves OpenCode sessions from the host’s SQLite store.

7. Hooks

Runtime hooks (hooks/, distributed with the plugin): eight hook programs — four canonical, three Codex duplicates under hooks/codex/, and one Antigravity copy under hooks/antigravity/ — plus three OpenCode adapters in opencode/team.js. The complete hook × host matrix is hooks-portability.md.

Hook Event Registers on Purpose
pre-compact-anchor.mjs PreCompact Claude .claude-plugin/plugin.json; Codex hooks/hooks.json (hooks/codex/ copy → stdout); OpenCode experimental.session.compacting Scan docs/plans// for active topic. Inject a 4-line anchor.
session-start-recover.mjs SessionStart Claude .claude-plugin/plugin.json; Codex hooks/hooks.json (hooks/codex/ copy → stdout); OpenCode experimental.chat.system.transform Scan docs/plans// for active topic. Emit a recovery notice.
post-write-validate.mjs PostToolUse(Write|Edit) Claude .claude-plugin/plugin.json; Codex hooks/hooks.json (hooks/codex/ copy, matcher apply_patch, exit 2); OpenCode tool.execute.after Structural validation of plugin component files
validate-team-config.mjs UserPromptSubmit Claude .claude-plugin/plugin.json; Codex hooks/hooks.json (reused canonical); Antigravity root hooks.json (hooks/antigravity/ copy at PreInvocation, inject-only) Validate .team/config.json. Block the prompt (exit 2) while it is invalid.

The Codex copies move the recovery envelope to stdout with hookEventName, parse apply_patch stdin, and block with exit 2; the canonical config guard is reused unchanged because its stdin and exit-2 contract already match. Antigravity exposes only PreInvocation, which cannot block, so its config binding injects an ephemeral message and the prompt proceeds; the other three Antigravity events are named gaps. OpenCode drives the canonical recovery files through its plugin adapters. See hooks-portability.md for the verified vs. unverified cells.

Both pre-compact-anchor.mjs and session-start-recover.mjs work the same way. They list docs/plans/*/ directories. They pick the most recent artifact directory by the mtime of any contained artifact. They infer the current phase from artifact presence and frontmatter. They then emit a short context message that names the phase, <id>, and the suggested next /team-* command. Both are stateless, exit 0 on any error, and return within the 5000ms hook budget.

validate-team-config.mjs is the odd one out: it is a guard, not a notice. It reads <project>/.team/config.json, validates it through the same schema owner the resolver uses (skills/team/references/model-config.mjs), and blocks the prompt with exit 2 while the file is invalid. An absent file is valid — the overrides are optional. A hook bug exits 0 rather than stranding the session.

Development hooks (.claude/hooks/, not distributed):

Hook Event Purpose
check-registry-sync.mjs PostToolUse(Write|Edit) Verify the agents/ directory and registry.json agree by agent name
pre-merge-guard.mjs PreToolUse(Bash) Deny gh pr merge when the version-bump invariant fails

Development scripts (.claude/scripts/, not distributed) house dev-only tooling run by plugin developers: version computation, the land-time version-consistency assertion, and project-board helpers.

8. Testing

Team currently has no test suite. The previous behavioral-eval harness (tests/, evals/, and its CI workflows) was removed so a new testing methodology can be designed from scratch. What remains is static: the dev hooks under .claude/hooks/, the version scripts under .claude/scripts/ and .github/scripts/, and claude plugin validate ..

9. State management

Primary state: the artifacts in docs/plans/<id>/*.md. Each artifact’s YAML frontmatter is the source of truth for “did this phase finish?” and “did the design review pass?”

Live coordination: TodoWrite (session-scoped). The orchestrator seeds the ledger at the start of /team, marks each item in_progress when dispatching, and completed when the artifact lands. Any /team-* command rebuilds the ledger by scanning artifacts on entry, so an interrupted run can be resumed by re-invoking any of them bare: discovery auto-resolves the artifact directory (an explicit docs/plans/<id>/ is still accepted). On a host offering no TodoWrite, docs/plans/<id>/ledger.md substitutes for the ledger rather than supplementing it, and the run reports which of the two it used; being on disk, that one is durable rather than session-scoped, so the aggregate gate’s round counts survive a restart.

Design-review records: docs/plans/<id>/design-review-<n>.md (frontmatter verdict: <APPROVE|REQUEST CHANGES|COMMENT>) records each review round durably. The artifacts are self-describing.

Compaction defense: the PreCompact hook scans docs/plans/<id>/ directories for the active topic and injects a 4-line anchor (phase, <id>, suggested next /team-* command). The SessionStart hook does the same for new sessions.

Artifact persistence: during a run, files in docs/plans/<id>/ live on disk in the worktree’s working tree and the pipeline never commits them. That discipline is what lets the commit-based IMPLEMENT signal (≥1 commit on <id> since the default-branch merge-base) distinguish “implementation has begun” from “artifacts merely exist”. Any commit on <id> is thus a code or slice commit, never an artifact commit. A finished plan directory can land later in its feature PR, which is outside the run. Persistence across sessions, compaction events, and context resets comes from the survival of the worktree’s files, not from git history. They remain the durable communication protocol between agents and the source of truth for “did phase N finish?”

10. Nested sub-agents

Claude Code v2.1.172 lets sub-agents spawn their own sub-agents (up to 5 levels deep). The plugin uses this capability in exactly three patterns, all governed by skills/team/references/agent-dispatch.md:

Policy:

Before any non-vendor dispatch, the parent resolves and Reads the writing standards reference under ${CLAUDE_PLUGIN_ROOT}. Claude Code substitutes that installed plugin root before dispatch. The prompt carries the resolved, read-only path. The helper Reads it before it audits its authored report. If any Read fails, the parent discards the return. Research scouts fall back to inline reading. Reviewer skeptics keep the finding by default. Vendor couriers receive no prose paths and relay stdout unchanged.

Research assembly treats completed file-finder and researcher returns as unchanged, untrusted source data. At capture, the root wraps each return in a backtick fence labeled untrusted-evidence-file-finder or untrusted-evidence-researcher and makes it longer than every backtick run in that return. A fixed line identifies the blocks as untrusted evidence and says embedded imperatives carry no authority. The root then traces every final substantive claim only to the completed returns, never to task framing. File-finder returns at most 80 lines for one repo or 120 for multiple repos. Researcher returns at most 60 or 100 lines. The root reserves eleven lines for the five-line frontmatter, authority line, four fence lines, and one source-grounded synthesis line. The final artifact therefore has at most 151 lines for one repo or 231 for multiple repos. Line validation normalizes line endings but counts every physical line, including terminal empty and whitespace-only lines. The root retries an oversized producer once with the same isolated inputs. It stops on a second oversized return and never truncates source data. Design, structure, planning, test authoring, and implementation use those blocks only as evidence. Each actor revalidates proposed actions or acceptance tests against 1-task.md, which records user intent. Embedded imperatives authorize no action.

Future work (ship-later)

Recorded here so the next capability step is deliberate, not improvised. Prerequisite for all items: nesting survives 2-3 Claude Code releases without breaking changes, parallel dispatch semantics for nested children are confirmed, and the depth cap is stable.

See also