teams-setup · diff

git:20260828.38cf6ac to git:20260828.c1a5290

33 added, 6 removed. Audit A to A.

---
name: teams-setup
description: "Creates and manages dynamic teams of domain agents. Triggers: create team, agent team, team status, cleanup team."
user-invocable: true
disable-model-invocation: true
argument-hint: "[prompt] [status|install|upgrade|enable|disable|uninstall|purge] [name]"
allowed-tools: [Read, Write, Edit, Glob, Grep, Bash, Agent, AskUserQuestion, Skill]
model: opus
---
<!-- brewcode-meta: version=6.1.4 content_version=6.1.0 generated_by=brewcode:teams-setup -->
<instructions>
# Teams
Manage dynamic teams of domain-specific agents with tracking framework.
**Arguments:** `$ARGUMENTS`
---
## Prompt contract
Position 1 of `$ARGUMENTS` is a **free-form prompt** (RU/EN) — the mode and the `[name]` positional are
optional and may follow in any order. Nobody types keys: resolve mode + team name FROM the prompt.
| Mode | EN keywords | RU keywords | Mutates? |
|------|-------------|-------------|----------|
| `status` | *(empty)*, `status`, `show`, `list`, `check` | `статус`, `покажи`, `что`, `проверь` | no |
| `install` | `install`, `create`, `setup`, `new team`, `build` | `установи`, `создай`, `настрой`, `новая команда` | yes |
| `upgrade` | `upgrade`, `update`, `tune`, `improve`, `retune` | `обнови`, `улучши`, `настрой лучше` | yes |
| `enable` | `enable`, `on`, `turn on`, `activate`, `restore` | `включи`, `активируй`, `верни`, `восстанови` | yes |
| `disable` | `disable`, `off`, `turn off`, `pause`, `park` | `выключи`, `отключи`, `пауза`, `приостанови` | yes |
| `uninstall` | `uninstall`, `remove`, `delete`, `clean up`, `tear down` | `удали`, `убери`, `сними`, `очисти` | yes, destructive |
| `purge` | `purge`, `wipe`, `nuke`, `delete everything`, `remove all` | `снеси`, `удали всё`, `вычисти`, `полностью удали` | yes, destructive |
1. Strip flags (`--skip-review`, `--review`). An explicit mode token anywhere wins outright, no scoring.
2. Else score modes by distinct whole-word keyword hits (table above). Highest unique score wins.
Tie with a destructive mode -> `AskUserQuestion`; tie with `status` -> `status`; tie of two mutating
modes -> the keyword appearing first; all zero -> **the documented default: `status` if the named
team already exists, else `install`** (`detect-mode.sh` already applies this default when the input
is empty or the first word is not a canonical mode).
3. Empty arguments -> the same default. `status` asks nothing; `install` and the other mutating
defaults ask ONE scoping question only when the answer changes what gets written.
4. Outcome-changing ambiguity -> ONE `AskUserQuestion` (max 4 questions) BEFORE any work.
5. A prompt that is not a bare `mode [name]` pair is still input, never an error: extract the team
NAME (and, for `install`, the team description) from the prose. **Never treat the first word of a
sentence as the positional `[name]`** — `"disable the payments team"` names team `payments`, not
`disable`; `detect-mode.sh`'s literal first-word parse is only correct for a bare `mode [name]`
shape, see Error Handling below for the prose case.
Then print this block ONCE, before the first action (`## Universal Prelude` Step 0.4):
```
PLAN — brewcode:teams-setup
INPUT: <arguments verbatim, or "(empty)">
MODE: <resolved> — <explicit | matched keyword: X | default>
SCOPE: <team name, agent count/roster, paths under .claude/teams/{name}/ and .claude/agents/>
DO: <2-5 imperative bullets>
RESULT: <what the user ends up holding>
```
Labels are literal; values follow the conversation language. `status` still prints it — asks nothing.
---
## Phase 1: Parse Arguments
**EXECUTE** using Bash tool:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/detect-mode.sh" "$ARGUMENTS" && echo "OK" || echo "FAILED"
```
Output: `MODE:`, `TEAM_NAME:`, `PROMPT:` (optional), plus the artifact-metadata scalars
`PLUGIN_VERSION:`, `CONTENT_VERSION:`, `GENERATED_BY:`, `LAST_UPDATED:`. Store all of them.
> **Artifact metadata — every file this skill writes.** `team.md` and every generated domain agent carry
> `version` = `PLUGIN_VERSION:`, `generated_by` = `GENERATED_BY:` (`brewcode:teams-setup`),
> `last_updated` = `LAST_UPDATED:`, and `doc_type: llm` on the agents. `team.md`'s header table ALSO
> carries `content_version` = `CONTENT_VERSION:`, right after `Version` — self-located by
> `detect-mode.sh` from THIS skill's own `SKILL.md` line-1 `brewcode-meta:` marker (the one
> `bump-version.sh` stamps at release), never copied from `PLUGIN_VERSION:` and never invented.
> Take the values from the output above — never hardcode a version, never call `date` a second time
> with a different format, and never stamp a "template version": the plugin version replaces it.
> `.claude/agents/intent-guard.md` is the ONE exception: `generate.sh emit-agent` stamps it with
> `generated_by: brewcode:superreview-setup`, and teams never touches those keys.
Resolve `INTENT_GUARD_POLICY` before a write: a new team defaults to `required`; an existing `team.md`
with `|Intent guard|required|` or `|Intent guard|legacy-absent|` keeps that exact value. When the row
predates this field, presence of an `intent-guard` roster member migrates to `required`; absence migrates
to `legacy-absent`. These are the only values. `required` requires the fixed review-only row;
`legacy-absent` forbids that row and MUST NOT add the role during upgrade.
Resolve `REPORT_ROOT` from the applicable project guidance before every `team.md` write. The narrowest
durable project instruction wins (for example, Dusk's Codex guidance requires `.codex/reports` even when
this Claude workflow performs the write); otherwise use `.claude/reports`. Store a normalized project-relative
path with no trailing slash. Reject absolute paths, `~`, `..` segments, backslashes, whitespace, doubled
slashes, unresolved `{...}` tokens, control characters, or shell metacharacters. Every slash-separated
segment MUST match `^[A-Za-z0-9._-]+$` and MUST NOT equal `.` or `..`; this rejects `$()`, backticks,
`;`, `&`, and `|` by construction. If equally specific applicable guidance declares two distinct report
roots, **STOP on the conflict** instead of selecting either. Never infer the report root from this plugin's
own defaults when project guidance declares one.
`MODE` is one of the canonical seven, in this order: `status | install | upgrade | enable | disable |
uninstall | purge`. On any `ERROR:` line: report it verbatim and **STOP**. Never guess a mode, and
never treat a canonical verb as a team name — `install enable` creates a team NAMED `enable`, so the
verb always comes first and the optional `[name]` positional after it.
> **How a team is enabled or disabled.** Claude Code discovers a project agent only through
> `.claude/agents/<name>.md`. `disable` renames each member to `<name>.md.disabled`; `enable` renames
> it back. The file body, `team.md`, `trace.jsonl`, `trace-archive.jsonl` and the cursor are untouched
> either way, so the toggle is fully reversible and loses no configuration and no history. It is NOT
> an uninstall: nothing is deleted. Under `required`, `intent-guard` is never parked — it is shared
> with `/brewcode:superreview-setup`, exactly as in UNINSTALL and PURGE. Under `legacy-absent`, no
> guard file or roster row is introduced.
---
## Universal Prelude (every mode)
### Step 0: Init + Validate + Confirm
1. Output: `Mode: {MODE}, Team: {TEAM_NAME}`
2. Load environment:
| Action | Command / Path |
|--------|----------------|
| Read agent template | `${CLAUDE_SKILL_DIR}/references/agent-template.md` |
| Read framework templates | `${CLAUDE_SKILL_DIR}/references/framework-files.md` |
| Check team dir | `.claude/teams/{TEAM_NAME}/` -- exists? |
| Check existing agents | `.claude/agents/` -- list all |
| If team.md exists | Read, show current roster |
| If trace.jsonl exists | Show entry counts via `trace-ops.sh read` |
- 3. If team exists, verify:
+ An absent `trace.jsonl` is valid before the first event or after cleanup: status reports zero events,
+ verification stays read-only, and `trace-ops.sh add` creates it safely on the first write. A present
+ trace target must be a non-symlink regular file.
+
+ 3. Preflight the durable tokenizer without network or mutation:
```bash
+ python3 -I -S "${CLAUDE_SKILL_DIR}/scripts/prepare-tokenizer.py" check
+ ```
+ If it is missing, retain the emitted `REPAIR: ... prepare` command. `status` reports the missing
+ prerequisite and does not run team verification. A mutating mode waits for step 5 approval before
+ preparation. If the preflight passes and the team exists, verify:
+ ```bash
bash "${CLAUDE_SKILL_DIR}/scripts/verify-team.sh" "TEAM_NAME_HERE" && echo "PASS" || echo "FAIL"
```
4. Print the **PLAN** block (`## Prompt contract` above) — once, before step 5's confirmation and
before any mutation. `status` prints it too, then skips straight to its report — no AskUserQuestion.
5. Mutating modes only — **ASK** using AskUserQuestion: "PLAN above. Continue?"
Options: "Yes, continue" | "No, I want changes" | "Cancel"
- "changes" -> AskUserQuestion for details, revise the PLAN and reprint it
- "Cancel" -> **STOP**
+ 6. After approval, prepare the isolated tokenizer when step 3 reported it missing, then preflight it
+ again. This explicit step is the only tokenizer install/network path; it downloads the exact
+ platform wheel and BPE into the user cache, verifies both SHA-256 values, creates a dedicated venv,
+ and installs the wheel with `--no-deps --no-index`:
+ ```bash
+ python3 -I -S "${CLAUDE_SKILL_DIR}/scripts/prepare-tokenizer.py" prepare \
+ && python3 -I -S "${CLAUDE_SKILL_DIR}/scripts/prepare-tokenizer.py" check
+ ```
+ **STOP on failure.** `verify-team.sh` and `count-tokens.py` never install, download, or use a
+ temporary runtime; they fail closed with the same repair command.
+
---
## Delegation (applies to EVERY Task spawn in this skill)
A big task handed to one agent = an agent gone for an hour: you cannot observe it, cannot correct
it, and it usually drifts off-target. One subagent = ONE bounded unit — one deliverable
(here: ONE agent file), ~<=5 files, ~<=10 steps. Bigger MUST be split into N tasks, all spawned
in ONE message. That is why agents are created one-per-spawn and reviews are fanned out.
Every spawn prompt MUST carry:
| Field | Content |
|-------|---------|
| GOAL | the overall task and why it exists — the point beyond the file edit |
| ROLE | what this agent owns; what it must NOT touch |
| SCOPE | exact paths/commands in bounds + explicit out-of-bounds |
| CONTEXT | what is already done, by whom, what runs in parallel — trimmed to what THIS agent needs |
| CONSUMER | who or what uses the result next, and the shape it must fit |
| DONE | acceptance criteria + the exact report shape you want back |
A bare one-line task is never enough. See C8 for the canonical spawn shape.
Every code/test brief MUST make the agent find the closest well-built counterpart in the repo and follow its principles - IN ADDITION to conventions/rules/docs, never instead.
---
## Mode: INSTALL (9 phases)
### C1: Project Analysis
Spawn 3-5 Explore agents in ONE message via Task tool:
| # | Focus |
|---|-------|
| 1 | Code structure: modules, packages, domains, architectural layers |
| 2 | Existing agents (`.claude/agents/`, `brewcode/agents/`, `~/.claude/agents/`) + Claude Code infrastructure |
| 3 | Tech stack: build files, frameworks, dependencies, languages |
| 4 | CI/CD, testing, deploy, infrastructure |
| 5 (optional) | Domain boundaries: business logic, API, data layer, UI |
All via `Task(subagent_type="Explore")`. Consolidate into single analysis document.
**For the new team's default `required` policy, also harvest the intent-guard facts** (agent #1 and #4
cover most of these; add explicit asks to their prompts).
These fill the placeholders of the shared `intent-guard.md.template` in C3 — an unharvested fact must be recorded
as `none` / `not present in this project`, never invented:
| Fact | Fills | Where to look |
|------|-------|---------------|
| Project name | `{PROJECT_NAME}` | repo dir, root `CLAUDE.md`, `package.json`/build file |
| Where original requirements live (tracker, issues, Slack, "chat only") | `{TRACKER_LABEL}` | `CLAUDE.md`, `.github/`, issue templates, CI links |
| Spec / design-doc paths or globs | `{SPEC_LOCATION}` | `.claude/specs/**`, `docs/`, `adr/` |
| Plan / task-board / task-graph paths | `{PLAN_LOCATION}` | `.claude/features/**`, `TASKS.md`, board files |
| Policy paths: root + nested `CLAUDE.md`, rules, conventions | `{POLICY_LOCATION}` | `CLAUDE.md`, `.claude/rules/**` |
| Planned scale / user count, testing policy, dependency policy, file-layout policy, architecture stance | `{PROJECT_INVARIANTS_TABLE}` | `CLAUDE.md`, rules, test dirs, manifests, module layout |
| 3-6 plausible drift instances in this repo's vocabulary | `{DRIFT_EXAMPLES_TABLE}` | derived from the invariants above |
| Cheap evidence commands (diffstat, manifest diff, test-file count, new-file list) for this stack | `{EVIDENCE_COMMANDS_BASH}` | build/test tooling found by agent #3 and #4 |
Also resolve and store `REPORT_ROOT` from applicable root/nested project guidance using the prelude rule.
An exact durable project path wins; guidance silence falls back to `.claude/reports`. Equal-specificity
conflicting report-root directives -> STOP. Validate the winning path before C2.6.
### C2: Team Proposal (interactive)
Based on analysis + PROMPT (if provided), propose 3 variants via AskUserQuestion.
New installs use `INTENT_GUARD_POLICY=required`: `intent-guard` is a fixed review-only anti-drift
member (asked-vs-delivered), outside the domain-agent count. The 5 / 10-12 / 15-20 counts describe
DOMAIN agents only. Show it as fixed in every new-install variant:
```
Fixed member (every variant, not counted):
| Agent | Domain | Mission |
| intent-guard | -- (review-only) | Compares what was ASKED vs what was DELIVERED; explicit invocation only |
Minimal (5 domain agents + intent-guard):
| Agent | Domain | Mission |
Balanced (10-12 domain agents + intent-guard) -- Recommended:
| Agent | Domain | Mission |
Maximum (15-20 domain agents + intent-guard):
| Agent | Domain | Mission |
```
Options: "Minimal (5)" | "Balanced (recommended)" | "Maximum (15-20)" | "Custom -- I'll specify"
If "Custom" -- second AskUserQuestion for free input; the new-install `required` policy stays fixed.
Final confirmation of agent list before proceeding. Existing `legacy-absent` teams are handled only by
UPGRADE and retain their explicit policy without adding `intent-guard`.
> If `.claude/agents/intent-guard.md` already exists (e.g. `/brewcode:superreview-setup` created it),
> label the fixed row `reuse (already present)` — C3-IG's `emit-agent` call will report `REUSE` and
> leave the file untouched.
**Agent names are globally unique across teams — REJECT a name another team already owns.** Two teams
listing the same agent share one file: one team's `upgrade` rewrites the other's member, and the other's
`uninstall`/`purge` is then blocked by the ownership check (`cleanup-flow.md` Step 3 step 0c), leaving
an undeletable roster row. Before showing the variants, run from the project root for every proposed name
(`intent-guard` excluded — it is shared BY DESIGN and exempt from this check):
```bash
for a in {PROPOSED_NAMES}; do
o=$(bash "${CLAUDE_SKILL_DIR}/scripts/agent-owners.sh" "$a") && echo "TAKEN $a <- $o"
done; echo "OK"
```
- exit 0 (any owner printed) -> the name is **TAKEN**. Drop it from the variant and propose a distinct
one — a domain-qualified rename such as `{name}-{TEAM_NAME}` or a different domain word. Never reuse,
never "join" the other team's agent.
- exit 2 (no owner) -> free, use it.
- exit 1 (refusal, reason on stderr) -> treat the name as TAKEN until the reason is fixed; report the
stderr line, do not guess.
Say which names were renamed and why in the confirmation before C3.
### C2.5: Model Selection (AskUserQuestion)
"Default model for domain agents: Opus (most reliable)."
| Model | Best for | Cost |
|-------|----------|------|
| opus | Complex domains, architecture, critical logic | High |
| sonnet | Standard domains, CRUD, testing, utilities | Medium |
| haiku | Simple utility agents, formatting, validation | Low |
Options: "Opus (recommended)" | "Sonnet" | "Haiku" | "Mixed -- I'll choose per agent"
If "Mixed" -- ask model per agent in C3. Store as `DEFAULT_MODEL` (default: opus).
> `DEFAULT_MODEL` applies to DOMAIN agents only. `intent-guard` keeps the `model: sonnet` its shared
> template ships — do not ask about it, do not override it.
### C2.6: Shared Contract Bootstrap (before agent discovery)
This gate MUST finish before any team-owned `.claude/agents/{name}.md` is written. An interrupted install
may leave a partial roster, but no discoverable compact profile may ever point at a missing shared contract.
1. Create `.claude/teams/{TEAM_NAME}/`.
2. Read `${CLAUDE_SKILL_DIR}/references/framework-files.md`; write `team.md` with substituted metadata,
validated `REPORT_ROOT`, `INTENT_GUARD_POLICY=required`, the byte-faithful `## Shared Agent Contract`,
exact "`intent-guard` is review-only, keeps its own output contract, and never implements." substitution,
the `## Agents` header,
and only the required fixed `intent-guard` row. Do not add domain-agent rows yet; C4 finalizes the
successfully created roster.
3. Create empty `trace.jsonl`; copy the project-local `trace-ops.sh` and make it executable.
4. Gate before C3: `team.md` exists, contains `## Shared Agent Contract`, the project-local tracer path,
and `A task traced \`took\` ends with exactly one terminal track: \`completed\` or \`failed\`.`
**STOP on any failure. Do not spawn or write an agent.** Resume by repairing this bootstrap first; never
strip shared rules from a profile until its target `team.md` passes the gate.
### C3: Agent Creation (agent-creator x N)
1. Read `${CLAUDE_SKILL_DIR}/references/agent-template.md`
1a. Confirm C2.6 completed. `.claude/teams/{TEAM_NAME}/team.md` is already written and gated; if missing
or incomplete, **STOP before the first spawn** and repair the bootstrap.
1b. **Re-run the C2 uniqueness check on the FINAL confirmed roster, immediately before the first spawn** —
the user may have typed names in the "Custom" branch that never passed it. Same script, same exit-code
reading. Any `TAKEN` name -> **do not spawn**; go back and rename it with the user first. Also refuse a
name whose `.claude/agents/{name}.md.disabled` exists with no live file: that is another install's parked
agent, and writing the live path recreates the dual-copy state both `enable` and `disable` refuse.
2. For each agent, spawn `Task(subagent_type="brewcode:agent-creator")` — ONE agent file per spawn, never a whole team. Prompt carries GOAL (build this one `{TEAM_NAME}` roster member; siblings own other domains), ROLE (owns `.claude/agents/{name}.md` only), SCOPE (that file; other agents, `team.md`, project source out), CONTEXT (settled mission/domain/project analysis, selected model, 3-4 sibling names; no trigger/domain overlap; the gated shared contract already exists), CONSUMER (C4 adds the final roster row; C5 reviews; the roster routes work), DONE:
- `description` <=100 chars (optimal ~80), single-line role + 2-3 triggers, no `<example>`;
- - body <=3200 bytes (~800 est-tokens), with exactly these ordered headings and no others: `## Mission`, `## Owned surfaces`, `## Exclusions`, `## Must-load references`, `## Unique invariants`, `## Unique verification`;
+ - body <=3200 bytes and <=800 exact `tiktoken==0.13.0` `o200k_base` tokens, with exactly these ordered headings and no others: `## Mission`, `## Owned surfaces`, `## Exclusions`, `## Must-load references`, `## Unique invariants`, `## Unique verification`;
- `## Must-load references` names `.claude/teams/{TEAM_NAME}/team.md` first;
- profile contains only domain-unique facts. `Task Acceptance Protocol`, `Return Contract`, `Trace Instructions`, `Colleagues`, `Scope Fit`, shared routing, and shared output rules stay only in `team.md`;
- placeholders substituted; return file path + description line.
Every spawn prompt MUST also carry the template path and the four metadata lines, resolved — the
subagent cannot see Phase 1's output, so **replace `{PLUGIN_VERSION}` and `{LAST_UPDATED}` below with
the literal values from the Phase 1 `PLUGIN_VERSION:` / `LAST_UPDATED:` lines before you send the
prompt.** A token that reaches the subagent ships verbatim into the agent file, and `setup-status`
then reports that agent `partial` forever. Those two spellings are the only sanctioned ones — never an
angle form, never a double brace:
```
CONTEXT (cont.): structure from ${CLAUDE_SKILL_DIR}/references/agent-template.md — read it first.
DONE (cont.): the frontmatter ends with exactly these four keys, in this order, AFTER the agent's
own keys (name, description, model, tools — leave those byte-untouched, `tools` above all):
doc_type: llm
version: "{PLUGIN_VERSION}"
generated_by: "brewcode:teams-setup"
last_updated: "{LAST_UPDATED}"
```
`verify-team.sh` re-reads every generated agent's frontmatter and FAILS on a wrong order, a missing
key or wrong quoting, so a prompt that shipped a token does not pass C4.
3. Batch 3-4 agents in parallel per message
4. After each batch, optimize without changing the six-heading contract:
```
Task(subagent_type="brewtools:text-optimizer", prompt="Light-optimize .claude/agents/{agent-name}.md; preserve its exact six ordered headings, team.md reference, names/numbers/negations/scope. Output metrics.")
```
> `brewtools` not installed (`text-optimizer` unavailable) — skip the pass, agents stay as written.
> **Never run the optimizer on `.claude/agents/intent-guard.md`.** Its frontmatter `description`
> is deliberately short and review-only; an optimizer pass may reword, lengthen or reflow it into
> a normal domain-agent description, which would make it compete for auto-activation. Excluded.
#### C3-IG: intent-guard (`required` policy, exactly once)
`.claude/agents/intent-guard.md` has exactly ONE writer: `generate.sh emit-agent`, shared with
`/brewcode:superreview-setup`. Never author this file from the template yourself, and never spawn an agent
to author it — that would fork the file into two divergent pipelines. `agent-creator` appears in this
phase only as a post-processor that replaces three seeded BLOCKs.
**Step 1 — emit.** Run from the project root, exporting the C1 facts. Unharvested fact -> `none` /
`not present in this project`; never invent a tracker, a path or a ticket id.
**EXECUTE** using Bash tool (substitute the C1 values first):
```bash
PROJECT_NAME="PROJECT_NAME_HERE" \
TRACKER_LABEL="TRACKER_LABEL_HERE" \
SPEC_LOCATION="SPEC_LOCATION_HERE" \
PLAN_LOCATION="PLAN_LOCATION_HERE" \
POLICY_LOCATION="POLICY_LOCATION_HERE" \
bash "${CLAUDE_SKILL_DIR}/../superreview-setup/scripts/generate.sh" emit-agent && echo "OK" || echo "FAILED"
```
It creates-or-reuses ONLY `.claude/agents/intent-guard.md` (superreview does not need to have run) and
prints exactly one `INTENT_GUARD:` line on STDOUT: `INTENT_GUARD: CREATED <path>`,
`INTENT_GUARD: REUSE <path>` or `INTENT_GUARD: MIGRATED <path>` (a pre-standard file of ours, restamped
in place — metadata only, tailored body preserved). Diagnostics (e.g. "recreating from template") go to
stderr and never add a second status line.
> **STOP if FAILED** -- report the script output; do not fall back to hand-authoring the file.
**Step 2 — sanity-check the emitted file** (a pre-existing file may be empty, truncated or
placeholder-laden; `-f` alone proves nothing). This runs on the REUSE path too, where `$f` is somebody's
already-adapted agent whose evidence block legitimately holds shell expansions — so strip `${VAR}` FIRST
and match bare tokens on what is left. Without the strip a `${BASE}` scores as an unresolved placeholder,
and this step's remedy is `rm -f`: it would delete a tailored file.
```bash
f=.claude/agents/intent-guard.md
[ -s "$f" ] && grep -q '^name: intent-guard' "$f" \
&& ! sed 's/\${[A-Z_][A-Z_]*}//g' "$f" | grep -q '{[A-Z_]\{2,\}}' && echo "SANE" || echo "CORRUPT"
grep -qF '<!-- generated_by: brewcode:superreview-setup' "$f" 2>/dev/null && echo "OURS" || echo "FOREIGN"
```
- `CORRUPT` + `OURS` -> the file came out of this pipeline, so `rm -f .claude/agents/intent-guard.md`,
re-run Step 1 once (a fresh emit is now a `CREATED`), re-check. Still `CORRUPT` -> **STOP** and
report; do not patch it by hand.
- `CORRUPT` + `FOREIGN` -> **STOP. Never `rm` it.** An unstamped file is the project's own agent and its
`{TOKENS}` may be its own convention; deleting it is the data loss this check exists to prevent
(`emit-agent` already REUSED it byte-untouched and printed the tokens as a conflict on stderr).
Report the path and the tokens and let the user decide.
**Step 3 — adapt the seeded BLOCKs.** Only on `INTENT_GUARD: CREATED`. On `REUSE` or `MIGRATED` skip this
step entirely: the existing file is already project-adapted and must not be rewritten or "refreshed".
`emit-agent` seeds three BLOCKs with GENERIC marked defaults. Spawn ONE
`Task(subagent_type="brewcode:agent-creator")`, alone (not batched with the domain agents), to replace
them with project-specific content:
```
Task(subagent_type="brewcode:agent-creator", prompt="
GOAL: team '{TEAM_NAME}' has its fixed review-only member intent-guard — the anti-drift check that
compares what was ASKED against what was DELIVERED. The file is ALREADY WRITTEN by
superreview-setup/scripts/generate.sh emit-agent with generic placeholder content in three BLOCKs.
Your only job is to tailor those three BLOCKs to this project.
ROLE: you own exactly three marked BLOCKs inside .claude/agents/intent-guard.md:
PROJECT_INVARIANTS_TABLE, DRIFT_EXAMPLES_TABLE, EVIDENCE_COMMANDS_BASH.
You do NOT author this agent and you do NOT re-instantiate it from any template.
SCOPE: Edit only the content of those three BLOCKs, in place.
EACH REPLACEMENT MUST CONSUME ITS MARKER. Every seeded BLOCK ends in its own
`<!-- SEEDED-DEFAULT: ... -->` line. Key each Edit on that marker: `old_string` = the
seeded block PLUS its marker line, `new_string` = your project-specific replacement
WITHOUT any marker. A surviving marker is what makes a skipped adaptation detectable —
`generate.sh validate` reports any file that still carries one as UNTAILORED.
HARD out of bounds — a single byte changed here is a failed task:
- the frontmatter (name, description, model: sonnet, tools, color, maxTurns). The
description is <= 100 chars, review-only, explicitly-invoked BY DESIGN; do NOT rewrite,
lengthen or 'improve' it. This overrides any default description-authoring habit.
- the file header, every heading, and every other section of the file
- the shared template, other agent files, team.md, trace.jsonl, project source
CONTEXT: C1 project analysis is settled — use these facts, invent nothing:
PROJECT_INVARIANTS_TABLE = from C1: planned scale/user count, testing policy, dependency
policy, file-layout policy, architecture stance
DRIFT_EXAMPLES_TABLE = 3-6 drift instances in THIS repo's vocabulary
EVIDENCE_COMMANDS_BASH = cheap evidence commands for THIS stack (diffstat, manifest diff,
test-file count, new-file list)
Unknown fact -> write 'none' / 'not present in this project'. Never fabricate a tracker,
a path or a ticket id. Do not add a Scope Fit block, Task Acceptance Protocol, trace
instructions or a Domain Instructions section — this agent has no code domain.
CONSUMER: /brewcode:superreview-setup spawns this same file by name during review, and C4 adds its row to
.claude/teams/{TEAM_NAME}/team.md — the file name and agent name stay exactly 'intent-guard'.
DONE: three BLOCKs project-specific, all three SEEDED-DEFAULT markers gone (consumed by the
replacements), everything else byte-identical to what emit-agent wrote.
Report: path + the three BLOCK contents + confirmation that frontmatter and header are untouched.
")
```
**Step 4 — verify.** FOUR counts, one grep per line, in this order. Each pattern matches the ARTIFACT,
never prose ABOUT it: the emitted agent legitimately keeps a tail comment that NAMES the stripped
`TEMPLATE HEADER`, so an unanchored `grep -c 'TEMPLATE HEADER'` reports `1` on every healthy file and
turns this gate into an unpassable loop. Match the header's opening line, not the phrase. Same reason the
placeholder count strips `${VAR}` first: `{PROJECT_NAME}` is a token, `${CLAUDE_PLUGIN_ROOT}` in an adapted
evidence command is not, and only a strip-then-match tells them apart — a `$`-guard inside the pattern
mis-handles adjacent tokens. `|| true` on every line: zero matches is the happy path for three of the four
counts (repo rule avoid#7), and a count must still PRINT under `set -o pipefail`, especially when it is the
one going red.
```bash
f=.claude/agents/intent-guard.md
sed 's/\${[A-Z_][A-Z_]*}//g' "$f" | grep -c '{[A-Z_]\{2,\}}' || true # 0 — unresolved placeholder
grep -c '^<!-- TEMPLATE HEADER' "$f" || true # 0 — header comment not stripped by emit
grep -c '^name: intent-guard' "$f" || true # 1 — frontmatter name key intact
grep -cF '<!-- SEEDED-DEFAULT:' "$f" || true # 0 — every seeded BLOCK marker consumed
```
Must print `0`, `0`, `1`, `0`. A non-zero last count means an adaptation left its marker (or skipped
the block) and `generate.sh validate` will report the agent `UNTAILORED`.
> **STOP if not** -- re-spawn Step 3 once with the offending lines named.
Report `intent-guard: created (adapted)` or `intent-guard: reused (already present)` and continue to
C4. Either way a `required` team gets its `team.md` row. This phase is skipped for an existing
`legacy-absent` team; never emit or adapt the agent merely to upgrade that team.
### C4: Roster Finalization + Verification
1. Re-check the C2.6 bootstrap before editing the roster. Missing/malformed shared contract, unsafe or
unresolved report root, or wrong policy-conditional intent-guard sentence -> **STOP**;
never finalize discoverable agents against an absent authority.
2. Finalize `team.md` from `${CLAUDE_SKILL_DIR}/references/framework-files.md`: preserve the bootstrapped
Shared Agent Contract byte-faithful, add one compact domain row per successfully created agent, and
apply the explicit intent policy (`required` retains the fixed row; `legacy-absent` has no row). Then
`touch trace.jsonl`. No confirmed-but-unwritten agent enters the roster.
Then install the **project-local tracer** the generated agents call. A `.claude/agents/*.md` file
is not plugin-owned, so `${CLAUDE_PLUGIN_ROOT}` is NOT substituted inside it and no
`*_PLUGIN_ROOT` env var exists — the only path an agent can rely on is a repo-relative one:
```bash
cp "${CLAUDE_SKILL_DIR}/scripts/trace-ops.sh" ".claude/teams/TEAM_NAME_HERE/trace-ops.sh" && \
chmod +x ".claude/teams/TEAM_NAME_HERE/trace-ops.sh" && echo "OK" || echo "FAILED"
```
> **STOP if FAILED** — without it every agent's trace call is a no-op, STATUS reports 0 tasks and
> UPGRADE misclassifies the whole roster as `Inactive`.
> Re-copy it in UPGRADE too (`cp` is idempotent) so a team created by an older version gains it.
`team.md` MUST carry `|Intent guard|required|` plus an `intent-guard` row (trailing `Kind` column =
`review-only`, trailing `Version` column = `PLUGIN_VERSION:`), whether C3-IG created or reused it.
Under `legacy-absent`, it MUST carry `|Intent guard|legacy-absent|` and no such row. `Agents | {N}`
counts DOMAIN agents only.
The header table MUST carry these four rows, adjacent and in exactly this order, filled from the
Phase 1 `PLUGIN_VERSION:` / `CONTENT_VERSION:` / `GENERATED_BY:` / `LAST_UPDATED:` lines:
```markdown
| Version | {PLUGIN_VERSION} |
| Content version | {CONTENT_VERSION} |
| Generated by | brewcode:teams-setup |
| Last update | {LAST_UPDATED} |
```
No placeholder token may survive into the written file — a literal `{PLUGIN_VERSION}` in `team.md`
means substitution never happened.
+ Add `|Agent defaults|active;{LAST_UPDATED};domain;{PLUGIN_VERSION}|`. A domain row using all four
+ defaults keeps the seven-column shape but leaves those cells empty: `|name|domain|mission|||||`.
+ Write all four cells only for an override; the fixed review-only `intent-guard` row stays explicit.
+
Keep roster `Domain`/`Mission` cells terse; agent profiles own detail. For up to 13 domain agents,
- the complete written `team.md` (metadata + shared contract + every row) MUST be <=2800 characters,
- i.e. `ceil(chars/4) <=700` estimated tokens. Measure the full substituted file, not the empty template;
+ the complete written `team.md` (metadata + shared contract + every row) MUST be <=2800 characters
+ and <=700 exact `tiktoken==0.13.0` `o200k_base` tokens. `verify-team.sh` fails closed when the
+ approved durable runtime or hash-verified cache is absent/mismatched; only Universal Prelude step 6
+ prepares it. Measure the full substituted file, not the empty template;
if over, compress only roster wording without dropping members, columns, policy, or contract facts.
3. Verify:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/verify-team.sh" "TEAM_NAME_HERE" && echo "PASS" || echo "FAIL"
```
> **STOP if FAIL** -- fix missing files before continuing.
4. AskUserQuestion: final report + suggest `/brewcode:teams-setup status {TEAM_NAME}`
### C5: Quorum Review
Spawn 3 reviewer agents in ONE message via Task tool. `REVIEWER` (here and in C7/C9) = the
project's reviewer agent from `.claude/agents/`, else `general-purpose`.
> **`intent-guard` is never the `REVIEWER`.** It is not a general reviewer: it only compares
> asked-vs-delivered on a real delivery, and it has no code domain. Never select it for the
> C5/C7/C9 pipeline role, and never as an implementation owner in C8 or U4.
| # | Focus |
|---|-------|
- | 1 | Profile contract: body only (frontmatter excluded) <=3200 bytes (~800 est-tokens); exactly six ordered body headings (`Mission`, `Owned surfaces`, `Exclusions`, `Must-load references`, `Unique invariants`, `Unique verification`); `.claude/teams/{TEAM_NAME}/team.md` loaded first; no repeated shared-contract heading/rule |
+ | 1 | Profile contract: body only (frontmatter excluded) <=3200 bytes / <=800 exact `tiktoken==0.13.0` `o200k_base` tokens; exactly six ordered body headings (`Mission`, `Owned surfaces`, `Exclusions`, `Must-load references`, `Unique invariants`, `Unique verification`); `.claude/teams/{TEAM_NAME}/team.md` loaded first; no repeated shared-contract heading/rule |
| 2 | Domain accuracy: correct scope, tool selection, model fit, description triggers |
| 3 | Architecture: no domain overlaps; owned surfaces/exclusions/routing agree with the roster; acceptance/tracing/returns/colleagues/scope-fit exist once in `team.md` |
`.claude/agents/intent-guard.md` is reviewed under DIFFERENT criteria — it is an instantiated shared
template, not an authored domain agent. Judge only: placeholders all resolved, template header stripped,
frontmatter identical to the template (short review-only description, `model: sonnet`, read-only tools),
project facts accurate and not invented. Do NOT judge it on the six-heading domain profile, domain fit/scope,
description triggers, acceptance, scope-fit, shared return or tracing — it has none by design, and
"add the missing sections" is a FALSE POSITIVE here. Never propose lengthening its description.
Each reads ALL agent files in `.claude/agents/` and outputs:
```
FILE: .claude/agents/{name}.md
SEVERITY: critical/important/minor
ISSUE: description
FIX: suggested fix
```
### C6: Consensus Filter
**Quorum threshold: 2/3 agreement = confirmed.** Match criteria: same file + same area (+/- 5 lines or same section) + same category (instruction/domain/architecture/trigger).
| Outcome | Action |
|---------|--------|
| 2/3+ confirm | Mark **confirmed**, keep severity from highest reporter |
| 1/3 only | Log as **unconfirmed**, skip |
| Minor severity (all reporters) | Log but skip fix |
### C7: Verification
```
Task(subagent_type=REVIEWER, prompt="
Verify these findings against actual agent files. For each:
1. Read the agent file
2. Check if the issue actually exists
3. Mark: VERIFIED or FALSE_POSITIVE
{confirmed_findings}
")
```
Filter out false positives. Final list = verified critical + important issues.
### C8: Fix
For each verified critical/important issue:
```
Task(subagent_type="brewcode:agent-creator", prompt="
GOAL: team '{TEAM_NAME}' was just generated and quorum-reviewed; this task clears ONE
confirmed defect so the roster ships clean.
ROLE: you own {agent_file} only. Do NOT touch other agent files, team.md, trace.jsonl,
CLAUDE.md, or project source.
SCOPE: {agent_file}. Out of bounds: everything else.
CONTEXT: C3 already wrote the whole roster and C5-C7 quorum-reviewed it; this finding is
verified (2/3 reviewers + C7 double-check) — do NOT re-litigate it. Up to 3 sibling
agent-creators fix other agent files in this same batch; team.md already lists the final
roster, so do not rename the agent or change its domain.
Read `${CLAUDE_SKILL_DIR}/references/agent-template.md` first; it is the canonical domain-profile
shape. For a domain agent, preserve exactly its six ordered body headings and shared-team reference.
ISSUE: {description}
FIX: {suggested_fix}
SEVERITY: {severity}
CONSUMER: C9 re-verifies your file for "issue resolved + no regression", and the team
manifest .claude/teams/{TEAM_NAME}/team.md must stay accurate — keep name, domain and
description shape intact so its roster row still matches.
DONE: fix applied and validated. Domain-agent body (frontmatter excluded) <=3200 bytes, exactly the
canonical six ordered headings, team.md loaded first, no shared contract duplicated. Report:
file | what changed | validation result.
")
```
Batch: up to 3 parallel per message. Minor issues skipped.
> If `{agent_file}` is `.claude/agents/intent-guard.md`, add to the ROLE: frontmatter is frozen —
> the description stays short and review-only, tools stay read-only, `model: sonnet` stays. Only
> placeholder content (project facts, invariants, drift examples, evidence commands) may be fixed.
### C9: Re-verify
```
Task(subagent_type=REVIEWER, prompt="
Re-verify these fixes. For each:
1. Read the fixed agent file
2. Check original issue is resolved
3. Check no regression introduced
4. For every domain agent, hard-gate exactly one single-line description <=100 characters and the
body only (frontmatter excluded): <=3200 bytes; exactly
`Mission`, `Owned surfaces`, `Exclusions`, `Must-load references`, `Unique invariants`,
`Unique verification` in order with no other headings; team.md first; no shared rule duplicated.
`intent-guard` is exempt from this six-heading gate and keeps its frozen review-only contract.
Mark: FIXED or REGRESSION
{fixes_applied}
")
```
| Outcome | Action |
|---------|--------|
| All FIXED | Pipeline complete, proceed to Epilogue |
| REGRESSION found | Return to C8 for that file (max 2 cycles) |
| Still failing after 2 cycles | Log as unresolved, proceed to Epilogue |
> To skip review pipeline: add `--skip-review` to `install` arguments.
> To run review on existing team: `/brewcode:teams-setup upgrade {TEAM_NAME} --review`
---
## Mode: STATUS (read-only)
No modifications. Read + report only.
1. Read `.claude/teams/{TEAM_NAME}/team.md`
2. Read trace data:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/trace-ops.sh" read ".claude/teams/{TEAM_NAME}" && echo "OK" || echo "FAILED"
```
Parse JSONL: group by `src` (agent) and `k` (kind). Compute per-agent stats from `k=track` (took/refused/completed/failed counts), issues from `k=issue`, insights from `k=insight`.
**Output:**
```markdown
# Team Status: {TEAM_NAME}
## Summary
| Metric | Value |
|--------|-------|
| Agents | {N} |
| Tasks tracked | {N} |
| Success rate | {%} |
| Open issues | {N} (high: {N}, critical: {N}) |
| Insights | {N} |
| Last activity | {date} |
## Per Agent
| Agent | Tasks | Success | Refused | Issues | Insights | Health |
|-------|-------|---------|---------|--------|----------|--------|
## Recommendations
```
Health:
| Label | Criteria |
|-------|----------|
| Healthy | >70% success, active |
| Needs tuning | 30-70% success or many refusals |
| Underperforming/Inactive | <30% success or inactive |
Recommendations: underperformers -> suggest `/brewcode:teams-setup upgrade`; >200 trace rows -> suggest `uninstall`; 0 activity -> suggest review.
No AskUserQuestion -- purely informational.
---
## Mode: UPGRADE (self-reflection)
### U1: Load & Parse
```bash
UPGRADE_CUTOFF=$(date -u +%Y-%m-%dT%H:%M:%SZ)
CURSOR=$(bash "${CLAUDE_SKILL_DIR}/scripts/trace-ops.sh" cursor ".claude/teams/{TEAM_NAME}")
bash "${CLAUDE_SKILL_DIR}/scripts/trace-ops.sh" read ".claude/teams/{TEAM_NAME}" --since "$CURSOR" && echo "OK" || echo "FAILED"
```
If cursor empty: all entries returned. If team not found -> **STOP**. If cursor exists and <10 post-cursor entries: expand to last 30 days.
Capture `UPGRADE_CUTOFF` before the initial cursor/trace read and keep it unchanged throughout U1-U4. Entries
created after that cutoff may be analyzed twice, but must never be skipped by advancing the cursor past them.
**Refuse to upgrade a PARKED member.** Every write in U4 targets `.claude/agents/{name}.md`; writing that
path while the member sits at `{name}.md.disabled` creates a live+parked dual copy — the state
`toggle-team.sh` now REFUSES in BOTH directions (`CONFLICT:`) and `verify-team.sh` FAILS on. Probe every roster member
before U2, from the project root:
```bash
for m in {AGENT_NAMES}; do
[ -f ".claude/agents/$m.md" ] || { [ -f ".claude/agents/$m.md.disabled" ] && echo "PARKED $m"; }
done; echo "OK"
```
- any `PARKED` row -> **STOP the whole mode.** Do not tune, do not regenerate, do not delete, do not
touch `team.md`. Report the parked members and the single remedy: `/brewcode:teams-setup {TEAM_NAME} enable`,
then re-run `upgrade`. Never "upgrade the live ones only" — a half-upgraded roster is what the guards exist to prevent.
- all members live -> continue.
### U1b: Shared Contract Migration Gate
Before U2 analysis or any U4 agent write, read
`${CLAUDE_SKILL_DIR}/references/framework-files.md` and upgrade `team.md` to the current shared contract.
For a legacy file with no `## Shared Agent Contract`, insert the canonical block before `## Agents`,
substituting `{TEAM_NAME}`, the current validated `REPORT_ROOT`, and policy-conditional guard wording while
preserving Created, roster rows, statuses, and history. Re-resolve `REPORT_ROOT` from current applicable
project guidance; do not preserve a stale plugin-default report path. Resolve and
write the explicit `Intent guard` field first: an existing intent-guard roster row -> `required`; no row
-> `legacy-absent`. Substitute the exact review-only guard sentence only for `required`; for `legacy-absent`
substitute an empty string so the shared contract never names a phantom role. Never synthesize the row on
the latter path. If a shared block exists but is
incomplete, replace that block from the canonical reference before proceeding. Re-copy `trace-ops.sh`,
then run `verify-team.sh`.
Legacy agent bodies remain byte-identical during this gate. **No agent may be tuned, regenerated, stripped,
deleted, or spawned until the shared contract passes.** A legacy-profile warning is safe; a shared-contract
failure stops the whole upgrade. Thus U4 can relocate repeated rules only after their destination exists.
### U2: Analyze Performance
Filter post-cursor trace: `k=track` for task stats, `k=issue` for problems, `k=insight` for patterns.
| Status | Criteria | Action |
|--------|----------|--------|
| Healthy | >70% success, active | No changes |
| Needs tuning | 30-70% success or many refusals | Update instructions |
| Underperforming | <30% success | AskUser: update or delete+create new |
| Inactive | 0 records | AskUser: delete or keep |
> Under `required`, `intent-guard` is EXCLUDED from this table. It does not trace and is invoked only
> during review, so 0 records is normal and never grounds for deletion or tuning. Under
> `legacy-absent`, there is no member to analyze. UNINSTALL enforces the same exclusion in
> `references/cleanup-flow.md` Step 3.
### U3: Present & Confirm
**ASK** using AskUserQuestion with analysis table and proposed actions (Update/Delete/No changes per agent).
Options: "Apply all" | "Let me choose" | "Show detailed analysis"
If "Let me choose" -> AskUserQuestion per agent. If "Show detailed" -> output full stats, then re-ask.
### U4: Apply Changes
| Agent Status | Action |
|--------------|--------|
| Needs tuning | `Task(subagent_type="brewcode:agent-creator")` update mode with tracking/issues/insights data |
| Underperforming (update) | Same as tuning |
| Underperforming (replace) | Delete agent file + create new via agent-creator |
| Inactive (delete) | Remove `.claude/agents/{name}.md` + update team.md status to `removed` |
> **Both delete rows run the ownership check first** — `cleanup-flow.md` Step 3 step 0c, same script,
> same exit-code table: `bash "${CLAUDE_SKILL_DIR}/scripts/agent-owners.sh" "{name}"`. More than one owner
> line, or exit 1 (owners unknown) -> **SKIP the delete**, keep the file, report it as shared/unknown and
> leave the roster row alone. `intent-guard` is never a candidate here at all (U2 note).
Immutable traits (Name, Base Role) -> delete + create new. Mutable traits (Character, Instructions) -> update during tuning.
Update `team.md` with current state: the header `Version` / `Content version` / `Generated by` /
`Last update` rows (that order) from the Phase 1 `PLUGIN_VERSION:` / `CONTENT_VERSION:` / `GENERATED_BY:`
/ `LAST_UPDATED:` lines, and — for each agent row you actually touched — its
`Updated` and `Version` cells. Rows left alone keep the version they were generated under.
A pre-5.0 `team.md` has neither the `Version` / `Generated by` header rows nor the trailing `Version`
column: ADD them here (append the column at the END of the roster table, never before `Agent`), do not
treat their absence as an error.
Each agent file you regenerate or tune gets its `version` / `last_updated` frontmatter keys refreshed
to the same values; `generated_by` stays `brewcode:teams-setup`. `intent-guard.md` is byte-untouchable.
Every domain agent touched here migrates to the current compact template: body only (frontmatter excluded)
- <=3200 bytes (~800 est-tokens),
+ <=3200 bytes / <=800 exact `tiktoken==0.13.0` `o200k_base` tokens,
exactly the six ordered headings, `.claude/teams/{TEAM_NAME}/team.md` first under `Must-load references`,
and no repeated acceptance/tracing/routing/return/colleague/scope-fit contract. Preserve every unique
fact while relocating shared rules to `team.md`. Untouched legacy agents keep their bodies; verifier
warnings identify the next migration set. `intent-guard.md` remains byte-untouchable.
Set cursor:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/trace-ops.sh" cursor ".claude/teams/{TEAM_NAME}" set "$UPGRADE_CUTOFF" && echo "✅" || echo "❌ FAILED"
```
---
## Mode: ENABLE
Un-parks a team that was previously `disable`d. Nothing is generated, nothing is analyzed — this is a
rename, and it is the exact inverse of DISABLE.
1. Team not found -> report and **STOP**. Never "enable" a team that was never installed.
2. Show what will move (no writes):
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/toggle-team.sh" "TEAM_NAME_HERE" enable --dry-run && echo "OK" || echo "FAILED"
```
3. Every member already live (`NOOP:` on all rows) -> say "team already enabled" and **STOP**. Do not
ask, do not rename.
4. Apply:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/toggle-team.sh" "TEAM_NAME_HERE" enable && echo "OK" || echo "FAILED"
```
5. `Edit` `team.md`: set each restored member's `Status` cell back to `active`, and refresh all FOUR
header rows — `Version` / `Content version` / `Generated by` / `Last update`, that order — from
`PLUGIN_VERSION:` / `CONTENT_VERSION:` / `GENERATED_BY:` / `LAST_UPDATED:`. The quartet always travels
together: this mode rewrote `team.md`, so the header records the version of THAT write. Do NOT touch
the per-agent `Version` cells — no agent body was rewritten, so no agent changed version.
6. Re-verify and report:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/verify-team.sh" "TEAM_NAME_HERE" && echo "PASS" || echo "FAIL"
```
`DISABLED_AGENTS:0` is the success signal. Tell the user the roster is visible to the NEXT session —
agent discovery is read at session start, so a rename mid-session is not picked up until reload.
---
## Mode: DISABLE
Takes the team out of the roster **without deleting anything**. Use it when a team should stop
self-selecting work but its instructions, trace history and archive must survive intact — a paused
team, not a removed one. `uninstall`/`purge` delete; `disable` does not.
1. Team not found -> report and **STOP**.
2. Show what will move (no writes):
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/toggle-team.sh" "TEAM_NAME_HERE" disable --dry-run && echo "OK" || echo "FAILED"
```
3. **ASK** using AskUserQuestion: "Disable team {TEAM_NAME}? {N} domain-agent files are parked as
`.md.disabled` — nothing is deleted, `enable` restores them. A required intent-guard stays live;
legacy-absent adds nothing."
Options: "Yes, disable" | "Uninstall instead (deletes agents, keeps archive)" | "Cancel"
- anything but "Yes, disable" -> switch to UNINSTALL or **STOP**
4. Apply:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/toggle-team.sh" "TEAM_NAME_HERE" disable && echo "OK" || echo "FAILED"
```
5. `Edit` `team.md`: set each parked member's `Status` cell to `disabled`, refresh all FOUR header rows
(`Version` / `Content version` / `Generated by` / `Last update`, that order) from the Phase 1 lines —
the quartet travels together on every mode that writes the file — and leave the per-agent `Version`
cells alone.
The roster rows themselves are never removed — a disabled team still has a full roster,
which is what `enable` reads back.
6. Re-verify and report: `verify-team.sh` prints `DISABLED` per parked member, `DISABLED_AGENTS:{N}`
and still exits PASS — a parked member is a state, not a missing file. Say the agents disappear from
the roster on the NEXT session.
---
## Mode: UNINSTALL
Read `${CLAUDE_SKILL_DIR}/references/cleanup-flow.md` and execute step by step:
1. Overview scan -> show trace.jsonl entry counts by kind
2. AskUserQuestion: what to clean (all / trace data / agents / step-by-step)
3. Trace cleanup (if selected) -- AskUserQuestion with archive options
4. Agents review (if selected) -- AskUserQuestion per agent if needed. `intent-guard` is never listed
and never deleted (cleanup-flow.md Step 3); deleting it would break `verify-team.sh` for the team
5. Summary report
Archive: entries appended to `.claude/teams/{TEAM_NAME}/trace-archive.jsonl`. Cursor reset after cleanup.
---
## Mode: PURGE
UNINSTALL's total variant: no selective menus, no archive kept. Removes the team's **entire**
footprint — the agents, the framework dir, the trace *and* its archive.
Read `${CLAUDE_SKILL_DIR}/references/cleanup-flow.md` "Step P: Purge" and execute it.
1. Show exactly what will be deleted (agent list from `team.md`, dir contents, byte sizes)
2. **ASK** using AskUserQuestion: "Purge team {TEAM_NAME}? This deletes {N} agent files and
`.claude/teams/{TEAM_NAME}/` including `trace-archive.jsonl`. Not recoverable."
Options: "Yes, purge" | "Uninstall instead (interactive, keeps archive)" | "Cancel"
- anything but "Yes, purge" -> switch to UNINSTALL or **STOP**
3. Execute the purge block in cleanup-flow.md Step P
4. Summary report
`intent-guard` is NEVER deleted, by purge either — it is shared with `/brewcode:superreview-setup`
and may belong to a superreview install that has nothing to do with this team.
Team not found -> report and **STOP**; do not "purge" a team that was never installed.
---
## Universal Epilogue (every mode)
### Step E1: Update CLAUDE.md (conditional)
Only for modes that change what the roster actually offers (INSTALL, UPGRADE with removals, ENABLE,
DISABLE — which flips the `Status:` line to `disabled` and leaves the table in place, UNINSTALL with
agent removal, PURGE — which removes the `## Teams` section entirely):
**ASK** using AskUserQuestion: "Update team info in CLAUDE.md?"
Options: "Yes, in project CLAUDE.md" | "Yes, in .claude/CLAUDE.local.md" | "No, skip"
Format to write:
```markdown
## Teams
Team: {TEAM_NAME} | Domain agents: {N} | Intent guard: {required (review-only) | legacy-absent} | Status: active
| Agent | Domain | Mission |
|-------|--------|---------|
When required, `intent-guard` is a review-only anti-drift check (asked vs delivered), shared with
`/brewcode:superreview-setup`, invoked explicitly by name during review, and never an implementation
owner. Under `legacy-absent`, do not add this paragraph or the role.
Protocol: agents self-select tasks, trace in `.claude/teams/{TEAM_NAME}/trace.jsonl`.
Manage: `/brewcode:teams-setup [status|install|upgrade|enable|disable|uninstall|purge] [name]`
```
### Step E2: Final Status
Always run STATUS mode logic after all changes: read team.md + trace.jsonl, compute stats, output Team Status table.
Exception: after PURGE there is no team left — output the purge summary instead.
---
## Output Format
```markdown
# teams [{MODE}]
## Detection
| Field | Value |
|-------|-------|
| Arguments | `{raw args}` |
| Mode | `{MODE}` |
| Team | `{TEAM_NAME}` |
| Prompt | `{PROMPT or none}` |
## Results
{Mode-specific output}
## Next Steps
- {recommendations}
```
---
## Error Handling
| Condition | Action |
|-----------|--------|
| `detect-mode.sh` prints `ERROR:` | Report the line verbatim. **STOP** — never fall back to INSTALL |
| Prose argument, first word not a canonical mode (e.g. `"create a new team for billing"`, `"убери команду платежей"`) | `detect-mode.sh` takes the literal first word as `TEAM_NAME` — do not trust that here. Apply `## Prompt contract` step 5: score the mode table against the full prompt, extract the team name from the noun phrase (not the first word), then re-invoke `detect-mode.sh` with a normalized `"<mode> <name> [rest]"` (or set `MODE`/`TEAM_NAME` directly) before continuing Phase 1 |
| PLAN block missing, or printed after Step 0.3 (`verify-team.sh`) / after any mutation started | Defect — **STOP**. A PLAN printed late does not count; return to Step 0.4, print it, then resume |
| Team not found (STATUS/UPGRADE/ENABLE/DISABLE/UNINSTALL/PURGE) | "Team '{TEAM_NAME}' not found. Run `/brewcode:teams-setup install {TEAM_NAME}`." **STOP** |
| ENABLE on a live team / DISABLE on a parked team | `toggle-team.sh` prints `NOOP:` for every row. Report "already {enabled\|disabled}" and **STOP** — do not rename, do not ask |
| `toggle-team.sh` prints `MISSING:` | A roster member has neither `.md` nor `.md.disabled`. **STOP** with the name — the team is broken, not disabled; run `upgrade` or re-create that agent |
| `toggle-team.sh` prints `SKIP:invalid agent id` / `INVALID:{N>0}` (or `verify-team.sh` FAILs the same row) | A roster value is not `^[a-z0-9][a-z0-9-]*$` — it is a path, and it would have been moved or deleted OUTSIDE `.claude/agents/`. The script touched nothing for that row and exits 1. **STOP**: show the row and have `team.md`'s `## Agents` table fixed by hand |
| `toggle-team.sh` prints `CONFLICT:{agent}` / `CONFLICT:{N>0}` (or `verify-team.sh` reports `CONFLICT` and FAILs) | That member has BOTH `.claude/agents/{a}.md` and `{a}.md.disabled`. BOTH directions refuse identically — `enable` would overwrite the live file, `disable` the parked one — all-or-nothing before any `mv`, so nothing moved and both bodies are byte-intact. `CONFLICT:{N}` is printed on EVERY toggle run, either action; `{N>0}` exits 1. **STOP**: name every conflicting member, have the user keep one copy and delete/rename the other, then re-run the SAME action. Never delete either copy yourself, never `--force` around it |
| `verify-team.sh` prints `DISABLED_AGENTS:{N>0}` | Expected on a disabled team, and it still exits PASS. Never report it as a failure and never "repair" it by regenerating the agents — `enable` is the fix |
| Team already exists (INSTALL) | Show roster, AskUserQuestion: "Upgrade instead?" |
| verify-team.sh FAIL | Show missing items, attempt fix, re-verify |
| No agents created (C3 failure) | Retry failed agents once, then report |
| 0 trace entries (UPGRADE) | Classify all agents as Inactive |
</instructions>