---
name: staff-session
description: "PM-GATED: ask first; never from subagent. Agent Teams collaborative planning/review for architectural decisions only. Modes: plan, review."
allowed-tools: ["Agent", "Read", "Write", "Bash", "Glob", "Grep", "TeamCreate", "TeamDelete", "TaskCreate", "TaskUpdate", "TaskList", "TaskGet", "SendMessage"]
argument-hint: "--mode plan|review --tier standard|full [--members \"patrik,zoli,...\"] <input>"
---

# Staff Session — Agent Teams Planning and Review Driver

The EM scopes the work, selects the team, creates the team, spawns all teammates, and is **freed**. The team works autonomously:
- **Debaters** (2-5, Opus, persona agents) — read input independently, research the codebase, form positions, debate peers via messaging, converge, write position documents, send DONE to synthesizer
- **the Director of Engineering / Synthesizer** (1, Opus) — Director of Engineering. Blocked until all debaters complete, then reads all positions and writes the final output through his ambition-calibrated lens. Represents all positions fairly but resolves contested topics with an eye toward what's achievable with AI execution capacity

**Lightweight tier falls through to single-reviewer dispatch via `/review` (plan) or `/review-code` (code) — no team created.**

## Arguments

`$ARGUMENTS`:
- `--mode plan|review` — required. `plan` for crafting a new plan from objectives; `review` for critiquing an existing artifact
- `--tier lightweight|standard|full` — required. `lightweight` routes to single-reviewer dispatch (`/review` for plan artifacts, `/review-code` for code artifacts). `standard` = 2 debaters. `full` = 3-5 debaters
- `--members "persona-a,persona-b,..."` — optional. Override auto-selection with explicit persona slugs (e.g., `"patrik,zoli"`)
- `<input>` — required. Plan mode: path to objectives document or free-text objectives. Review mode: path to the artifact to review

## Step 1 — Parse Arguments and Setup

Parse `$ARGUMENTS`:
- Extract `--mode` (plan|review) — required; fail with usage message if missing
- Extract `--tier` (lightweight|standard|full) — required; fail with usage message if missing
- Extract `--members` (optional) — comma-separated persona slugs
- Remaining text after flags is the `<input>` — artifact path or objectives

Generate run ID: `YYYY-MM-DD-HHhMM` (current timestamp, e.g., `2026-03-22-09h30`)

Record spawn timestamp:
```bash
date +%s
```

Generate topic slug from input (e.g., `camera-refactor-plan`, `pipeline-d-review`).

Create scratch directory:
```bash
mkdir -p tasks/scratch/staff-session/{run-id}
```

Set output path based on mode:
- **Plan mode:** `docs/plans/YYYY-MM-DD-{topic-slug}.md` (canonical output for `/enrich-and-review`)
- **Review mode:** `tasks/review-findings/YYYY-MM-DD-{topic-slug}-staff-review.md`

Set advisory path: `{scratch-dir}/advisory.md`

Announce: "Running `/staff-session --mode {mode} --tier {tier}` on '{topic}'."

## Step 2 — Tier Routing

**If `--tier lightweight`:**

Do NOT create a team. Route directly to `/review` (plan artifacts) or `/review-code` (code artifacts) with the specified member (or `patrik` as default if `--members` not provided).

Announce: "Routing to single-reviewer dispatch (`/review` or `/review-code`) for single-reviewer gut-check."

**STOP — the rest of this command does not execute.**

**If `--tier standard` or `--tier full`:** Continue to Step 3.

## Step 3 — Scope (EM Direct)

Write `{scratch-dir}/scope.md` per the template in `pipelines/staff-session/templates-and-fields.md` § Step 3. Plan mode: EM writes objectives and constraints only — never the plan. Review mode: EM provides artifact path and focus areas only — never pre-formed findings.

## Step 4 — Select Team Composition

**If `--members` specified:** Use those exact personas. Validate each slug maps to a known persona agent. Fail with a clear error if any slug is unknown.

**If `--members` not specified:** Auto-select based on domain signals from the input topic and scope.

**Important: the Director of Engineering is the synthesizer, not a debater.** the Director of Engineering cannot appear in the debater list — he reads all debater positions and produces the final output. If the user specifies `--members "patrik,zoli"`, reject with: "the Director of Engineering is the staff session synthesizer — he can't also debate. Choose a different second debater, or I'll auto-select one."

| Domain Signal | Default Pair |
|---|---|
| Architecture / infrastructure | `patrik` + `sid` |
| Game dev / Unreal | `sid` + `patrik` |
| Frontend / UI | `pali` + `fru` |
| Data science / ML | `camelia` + `patrik` |
| Cross-cutting / unclear | `patrik` + `sid` |

For `--tier full`: add domain experts on top of the default pair. Use judgment based on the input topic to identify which additional personas are most relevant.

Determine debater count:
- `standard`: 2 debaters
- `full`: 3-5 debaters (determined by domain signals and persona relevance)

Announce team composition to PM before creating the team:
> "I'll run this with **{Persona A}** and **{Persona B}** [+ **{Persona C}**...] debating, plus a staff synthesizer. Proceeding."

Persona slug → agent file mapping:

| Slug | Agent File |
|---|---|
| `patrik` | `coordinator/agents/staff-eng.md` |
| `sid` | `game-dev/agents/staff-game-dev.md` |
| `fru` | `web-dev/agents/staff-ux.md` |
| `pali` | `web-dev/agents/senior-front-end.md` |
| `camelia` | `data-science/agents/staff-data-sci.md` |
| `vp-product` | `coordinator/agents/vp-product.md` |

**Note:** `zoli` is NOT a valid debater slug — he is the synthesizer. See Step 6.

## Step 5 — Create Team and Tasks

**Order matters.** Task IDs from earlier steps are referenced in blocking chain setup.

### Create Team

```
TeamCreate(team_name: "staff-{topic-slug}")
```

### Create Tasks

**1. Synthesizer task** (created first — will be blocked by all debaters later):
```
TaskCreate(
  subject: "Synthesize all debater positions into final {plan|findings}",
  description: "Read all position documents from {scratch-dir}/. Cross-reference, resolve conflicts, write output to {output-path} and {scratch-dir}/synthesis.md. If advisory warranted, write to {scratch-dir}/advisory.md."
)
```
Save as `{synthesizer-task-id}`.

**2. Debater tasks** (one per persona — no blockers on creation):
For each debater persona:
```
TaskCreate(
  subject: "{Persona Name}: {mode} session on {topic}",
  description: "Read scope from {scratch-dir}/scope.md. {Plan mode: Research codebase, form architectural position, debate peers, write consensus-ready plan contribution.} {Review mode: Review artifact at {input-path}, form findings, debate peers, write final position.} Output to {scratch-dir}/{persona-slug}-position.md. Send DONE to synthesizer when complete."
)
```
Collect all debater task IDs as `[{debater-A-id}, {debater-B-id}, ...]`.

**3. Block synthesizer on all debaters:**
```
TaskUpdate(taskId: "{synthesizer-task-id}", addBlockedBy: [{debater-A-id}, {debater-B-id}, ...])
```

## Step 6 — Spawn All Teammates

Read the planner / reviewer / synthesizer prompt templates from `${CLAUDE_PLUGIN_ROOT}/pipelines/staff-session/`. For each debater, read the persona identity excerpt from its agent definition file (injected at `[PERSONA_IDENTITY]`). Fill ALL `[BRACKETED_FIELD]` placeholders before spawning — **see `pipelines/staff-session/templates-and-fields.md` § Step 6 for the full common/debater/synthesizer field list.**

**Spawn ALL teammates in a single message (parallel):**

```
Agent(
  team_name: "staff-{topic-slug}",
  name: "{persona-slug-A}",
  model: "opus",
  subagent_type: "coordinator:{persona-agent-name-A}",
  prompt: <filled debater prompt for persona A>
)
TaskUpdate(taskId: "{debater-A-id}", owner: "{persona-slug-A}")

Agent(
  team_name: "staff-{topic-slug}",
  name: "{persona-slug-B}",
  model: "opus",
  subagent_type: "coordinator:{persona-agent-name-B}",
  prompt: <filled debater prompt for persona B>
)
TaskUpdate(taskId: "{debater-B-id}", owner: "{persona-slug-B}")

[repeat for each additional debater in full tier]

Agent(
  team_name: "staff-{topic-slug}",
  name: "synthesizer",
  model: "opus",
  subagent_type: "coordinator:eng-director",
  prompt: <filled synthesizer prompt>
)
TaskUpdate(taskId: "{synthesizer-task-id}", owner: "synthesizer")
```

Persona slug → subagent_type mapping:

| Slug | subagent_type |
|---|---|
| `patrik` | `coordinator:staff-eng` |
| `sid` | `game-dev:staff-game-dev` |
| `fru` | `web-dev:staff-ux` |
| `pali` | `web-dev:senior-front-end` |
| `camelia` | `data-science:staff-data-sci` |
| `vp-product` | `coordinator:vp-product` |

## Step 7 — EM Is Freed

After spawning all teammates, announce:

> "Staff session running on '**{topic}**' with **{N} debaters** ({names}) + **1 synthesizer**.
>
> - Debate phase: floor 3 min, ceiling {MAX_MINUTES} min. Debaters research independently, form positions, and challenge each other.
> - Synthesizer unblocks when all debaters complete.
>
> I'm available for other work — I'll be notified when the synthesizer completes."

**You are now free to continue the conversation with the PM.** Do not poll, do not monitor, do not send WRAP_UP. The team self-governs via the timing and convergence protocol in `team-protocol.md`.

## Step 8 — On Completion Notification

When you receive a notification that the synthesizer task is complete:

1. Read the output at `{output-path}`. Verify it has substantive content (not just headers or a stub).

2. Mode-specific verification:
   - **Plan mode:** Verify the plan has an `## Implementation Plan` section with tasks, files, and steps in plan format (per `docs/wiki/writing-plans.md`). Verify `**Review:** Staff session ({participants}) — debated and synthesized. Ready for enrichment.` is present.
   - **Review mode:** Verify findings are structured with severities and persona attributions. Verify a `## Verdict` line is present.

3. Check for advisory: `test -f {scratch-dir}/advisory.md` — if the file exists, read it.

4. Commit the output (plain-git scoped — SC-DR-008, lessons.md:207):
   ```bash
   # Stage only the output files this session wrote (scratch dir contents + any plan/review artifact)
   git add -- {output-paths} && git commit -m "staff-session: {mode} — {topic-slug}" -- {output-paths}
   ```

5. Archive the paper trail:
   ```bash
   mkdir -p docs/research/archive/YYYY-MM-DD-staff-{topic-slug}
   cp -r {scratch-dir}/* docs/research/archive/YYYY-MM-DD-staff-{topic-slug}/
   ```

6. Remove scratch directory:
   ```bash
   rm -rf {scratch-dir}
   ```

7. Shut down the team:
   ```
   TeamDelete(team_name: "staff-{topic-slug}")
   ```

8. Commit cleanup (plain-git scoped — SC-DR-008, lessons.md:207):
   ```bash
   git add -- docs/research/archive/YYYY-MM-DD-staff-{topic-slug}/ && git commit -m "staff-session: archive + cleanup" -- docs/research/archive/YYYY-MM-DD-staff-{topic-slug}/
   ```

9. Present output to PM:
   - Mode-specific framing: plan mode → "Here's the staff session plan, ready for `/enrich-and-review`"; review mode → "Here are the synthesized findings"
   - Brief executive summary (2-3 bullets of the most important content)
   - Output path
   - If advisory exists: "The synthesizer flagged observations beyond scope — see `{scratch-dir}` (archived at `docs/research/archive/YYYY-MM-DD-staff-{topic-slug}/advisory.md`)."

## Error Handling

See `pipelines/staff-session/templates-and-fields.md` § Error Handling Matrix for the full failure-mode → action table (debater crash, synthesizer failure, DONE-not-received, debate loops, unknown slug, missing output).
