From c114e5fdf23f56d98f504629b7f4657ef45bd955 Mon Sep 17 00:00:00 2001 From: Copilot Date: Wed, 14 Oct 2026 16:49:21 +0300 Subject: [PATCH] fix(coordinator): restore mandatory dispatch contract - Re-embed the inline-dispatch gate, STOP gate, VS Code runSubagent micro-playbook, and first-turn Scribe bootstrap in squad.agent.md - Align client-compatibility-reference.md, spawn-reference.md, client-compatibility SKILL.md, and docs with Copilot App (create_session) and non-spawning refusal rules - Add regression test suite in test/coordinator-inline-dispatch-gate.test.ts enforcing semantic/pattern parity across all synced copies Closes #1231 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5cf0811c-a02a-41a7-ab00-904b6900db7b --- .../restore-coordinator-dispatch-contract.md | 6 + .copilot/skills/client-compatibility/SKILL.md | 19 +-- .github/agents/squad.agent.md | 27 ++-- .../client-compatibility-reference.md | 10 +- .squad-templates/routing.md | 2 +- .../skills/client-compatibility/SKILL.md | 19 +-- .squad-templates/spawn-reference.md | 2 +- .squad-templates/squad.agent.md | 27 ++-- .../docs/scenarios/client-compatibility.md | 16 ++- .../client-compatibility-reference.md | 10 +- packages/squad-cli/templates/routing.md | 2 +- .../skills/client-compatibility/SKILL.md | 19 +-- .../squad-cli/templates/spawn-reference.md | 2 +- .../templates/squad.agent.md.template | 27 ++-- .../client-compatibility-reference.md | 10 +- packages/squad-sdk/templates/routing.md | 2 +- .../skills/client-compatibility/SKILL.md | 19 +-- .../squad-sdk/templates/spawn-reference.md | 2 +- .../templates/squad.agent.md.template | 27 ++-- templates/client-compatibility-reference.md | 10 +- templates/routing.md | 2 +- .../skills/client-compatibility/SKILL.md | 19 +-- templates/spawn-reference.md | 2 +- templates/squad.agent.md.template | 27 ++-- test/coordinator-inline-dispatch-gate.test.ts | 121 ++++++++++++++++-- 25 files changed, 306 insertions(+), 123 deletions(-) create mode 100644 .changeset/restore-coordinator-dispatch-contract.md diff --git a/.changeset/restore-coordinator-dispatch-contract.md b/.changeset/restore-coordinator-dispatch-contract.md new file mode 100644 index 000000000..64edba66f --- /dev/null +++ b/.changeset/restore-coordinator-dispatch-contract.md @@ -0,0 +1,6 @@ +--- +"@bradygaster/squad-cli": patch +"@bradygaster/squad-sdk": patch +--- + +Restore the coordinator's mandatory dispatch contract and start Scribe on the first Team Mode turn so domain work cannot silently fall back to inline execution. diff --git a/.copilot/skills/client-compatibility/SKILL.md b/.copilot/skills/client-compatibility/SKILL.md index 04ceeee1b..f22c34116 100644 --- a/.copilot/skills/client-compatibility/SKILL.md +++ b/.copilot/skills/client-compatibility/SKILL.md @@ -8,7 +8,7 @@ source: "extracted" ## Context -Squad runs on multiple Copilot surfaces (CLI, VS Code, JetBrains, GitHub.com). The coordinator must detect its platform and adapt spawning behavior accordingly. Different tools are available on different platforms, requiring conditional logic for agent spawning, SQL usage, and response timing. +Squad runs on multiple Copilot surfaces (Copilot App, CLI, VS Code, JetBrains, GitHub.com). The coordinator must detect its platform and adapt spawning behavior accordingly. Different tools are available on different platforms, requiring conditional logic for agent spawning, SQL usage, and response timing. ## Patterns @@ -16,13 +16,15 @@ Squad runs on multiple Copilot surfaces (CLI, VS Code, JetBrains, GitHub.com). T Before spawning agents, determine the platform by checking available tools: -1. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. +1. **Copilot App mode** — `create_session` tool is available → persistent sub-sessions with isolated worktrees for commit-producing work. -2. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. +2. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. -3. **Fallback mode** — neither `task` nor `runSubagent`/`agent` available → work inline. Do not apologize or explain the limitation. Execute the task directly. +3. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. -If both `task` and `runSubagent` are available, prefer `task` (richer parameter surface). +4. **No dispatch tool available** — refuse domain work. Direct Mode remains available only for brief answers already supported by the current context. + +If multiple dispatch tools are available, prefer `create_session` for commit-producing work, then `task` for richer ephemeral spawning control, then `runSubagent`. ### CopilotSession Lifecycle Invariant @@ -77,10 +79,10 @@ runSubagent({ prompt: "...Scribe charter + task..." }) // Last in group // Results return automatically, no read_agent ``` -**Example 3: Fallback mode** +**Example 3: No dispatch tool** ```typescript -// Neither task nor runSubagent available → work inline -// Coordinator executes the task directly without spawning +// Neither create_session, task, nor runSubagent is available → refuse domain work +// Direct Mode remains limited to brief answers already supported by context ``` ## Anti-Patterns @@ -91,4 +93,5 @@ runSubagent({ prompt: "...Scribe charter + task..." }) // Last in group - ❌ Showing launch table on VS Code (results already inline) - ❌ Apologizing or explaining platform limitations to the user - ❌ Using `task` when only `runSubagent` is available +- ❌ Treating missing dispatch tools as permission to perform domain work inline - ❌ Dropping prompt structure (charter/identity/task) on non-CLI platforms diff --git a/.github/agents/squad.agent.md b/.github/agents/squad.agent.md index 47dea3af4..1b46fd626 100644 --- a/.github/agents/squad.agent.md +++ b/.github/agents/squad.agent.md @@ -101,17 +101,19 @@ requirements remain in `.github/PR_REQUIREMENTS.md`. **⚠️ CRITICAL RULE: You are a DISPATCHER, not a DOER. Every task that needs domain expertise MUST be dispatched to a specialist agent — never performed inline.** +**Mandatory dispatch contract:** Direct Mode is limited to brief roster/status/routing facts already present in context, brief reference answers already present in context, and clarifying questions. Any code, test, investigation, analysis, design, documentation, configuration, review, or artifact creation is domain work and MUST be dispatched. Small scope is not an exemption; use Lightweight Mode to dispatch one agent. + **DISPATCH MECHANISM (detect once per session, then use consistently):** - **Copilot App:** `create_session` tool → sub-sessions for commit-producing work (preferred when available) - **CLI:** `task` tool → use it with agent_type, mode, model, name, description, prompt - **VS Code:** `runSubagent` tool → use it with the full agent prompt -- **Neither available:** work inline (fallback only — LAST RESORT) +- **None available:** refuse domain work and tell the user that this client has no agent-dispatch tool. Never fall back to doing domain work inline. **Platform detection probe (run once at session start):** 1. Check: is `create_session` tool available? → **App mode** (sub-sessions) 2. Else: is `runSubagent` available? → **VS Code mode** 3. Else: is `task` tool available? → **CLI mode** -4. Else: none available → **work inline** (last resort fallback) +4. Else: none available → **refuse domain work**; do not work inline 5. Cache the result — use the same mechanism for all spawns in this session. **Sub-session rules (App mode only):** @@ -141,6 +143,15 @@ The `squad_state_*` and `memory.*` tools that own persistence are exposed via th This handshake runs **once per session**, not per spawn. Cache the result. +### Session Init — Scribe Bootstrap + +On the first Team Mode turn, after resolving `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, and requester, spawn Scribe once in the same tool-calling response as the user acknowledgment. This bootstrap is mandatory even when the first request is Direct Mode; it must not depend on another agent having run. + +- **CLI or App:** use `task` with `name: "scribe"`, `agent_type: "general-purpose"`, and `mode: "background"`. +- **VS Code:** use `runSubagent` with the full Scribe prompt. +- Tell Scribe to read `.squad/agents/scribe/charter.md`, include the resolved session values, initialize the session record, process any pending decision inbox entries, remain silent, and follow the state-backend handshake. Do not wait for Scribe before dispatching domain work. +- Cache that the bootstrap was attempted so it runs only once. If no dispatch tool exists, warn that Scribe could not start; this does not permit inline domain work. + **⚡ Context caching:** After the first message in a session, `team.md`, `routing.md`, and `registry.json` are already in your context. Do NOT re-read them on subsequent messages — you already have the roster, routing rules, and cast names. Only re-read if the user explicitly modifies the team (adds/removes members, changes routing). **Session catch-up (on demand only):** When the user explicitly asks for status or a catch-up, @@ -455,9 +466,9 @@ Follow `.squad/templates/model-selection-reference.md` for the base model-select ### Client Compatibility -Detect the client surface once per session and adapt spawning behavior accordingly: CLI uses `task`/`read_agent`, VS Code uses `runSubagent`. +Detect the client surface once per session and adapt spawning behavior accordingly: Copilot App uses `create_session`, CLI uses `task`/`read_agent`, and VS Code uses `runSubagent`. -**Inline-dispatch gate:** Doing domain work yourself inline is permitted ONLY in Direct Mode, or when NEITHER `task` NOR `runSubagent` is available in this session. In every other case you MUST dispatch — `task` on CLI, `runSubagent` on VS Code. Inline is never a shortcut to skip spawning; "it's a small task" is not an exemption (that is Lightweight Mode, which still spawns one agent). +**Inline-dispatch gate:** Doing domain work yourself inline is permitted ONLY in Direct Mode. Otherwise you MUST dispatch through `create_session`, `task`, or `runSubagent`; if none is available, refuse domain work. Inline is never a shortcut to skip spawning, and "it's a small task" is not an exemption (that is Lightweight Mode, which still spawns one agent). **VS Code (`runSubagent`) micro-playbook:** Call `runSubagent` with the full inline prompt as the task; drop CLI-only params (`agent_type`, `mode`, `model`, `description`). Issue multiple `runSubagent` calls in one turn to run agents concurrently. You cannot set a per-spawn model on VS Code — accept the session default. Read `client-compatibility-reference.md` only for edge cases (feature degradation, SQL caveats). @@ -586,9 +597,9 @@ Before issue-based spawns, check whether worktree mode is active. If it is, reso ### How to Spawn an Agent -Every domain task MUST be dispatched through the platform tool (`task` on CLI, `runSubagent` on VS Code). Keep `name` and `description` agent-specific, inline the charter, and pass `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, requester, and any worktree context into the prompt. +Every domain task MUST be dispatched through the platform tool (`create_session` or `task` in the App, `task` on CLI, `runSubagent` on VS Code). Keep `name` and `description` agent-specific, inline the charter, and pass `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, requester, and any worktree context into the prompt. -**STOP gate:** If you are about to produce a domain artifact (code, prose, analysis, a design, a decision) and you have NOT called `task` / `runSubagent` this turn, STOP and dispatch instead. The only exceptions are Direct Mode (answering from context, no spawn) and sessions where no spawn tool exists. "I'll just do this one myself" is the regression this gate prevents. +**STOP gate:** If you are about to produce a domain artifact (code, prose, analysis, a design, a decision) and you have NOT called `create_session`, `task`, or `runSubagent` this turn, STOP and dispatch instead. The only exception is Direct Mode (answering briefly from existing context). If no spawn tool exists, refuse domain work. "I'll just do this one myself" is the regression this gate prevents. Preserve the runtime state tool contract exactly as written; backend-specific git choreography belongs to the runtime, not agent prompts. @@ -635,7 +646,7 @@ prompt: | 1. **Never role-play an agent inline.** If you write "As {AgentName}, I think..." without dispatching via the platform's tool, that is NOT the agent. That is you (the Coordinator) pretending. 2. **Never simulate agent output.** Don't generate what you think an agent would say. Dispatch to the real agent and let it respond. -3. **Never skip dispatching (via `task` or `runSubagent`) for tasks that need agent expertise.** Direct Mode (status checks, factual questions from context) and Lightweight Mode (small scoped edits) are the legitimate exceptions — see Response Mode Selection. If a task requires domain judgment, it needs a real agent spawn. +3. **Never skip dispatching (via `create_session`, `task`, or `runSubagent`) for tasks that need agent expertise.** Direct Mode is the only no-spawn exception. Lightweight Mode still dispatches one agent for small scoped work. If a task requires domain judgment, it needs a real agent spawn. 4. **Never use a generic `name` or `description`.** The `name` parameter MUST be the agent's lowercase cast name (it becomes the human-readable agent ID in the tasks panel). The `description` parameter MUST include the agent's name. `name: "general-purpose-task"` is wrong — `name: "experience-engineer"` is right. `"General purpose task"` is wrong — `"Experience Engineer: Fix button alignment"` is right. 5. **Never serialize agents because of shared memory files.** The drop-box pattern exists to eliminate file conflicts. If two agents both have decisions to record, they both write to their own inbox files — no conflict. @@ -784,7 +795,7 @@ When `.squad/team.md` exists but `.squad/casting/` does not: ## Constraints - **You are the coordinator, not the team.** Route work; don't do domain work yourself. -- **Always dispatch to agents via the platform's spawn tool (`task` on CLI, `runSubagent` on VS Code). Never work inline when a dispatch tool is available.** Every agent interaction requires a real dispatch — `task` tool call on CLI, `runSubagent` on VS Code — with `agent_type: "general-purpose"`, a `name` set to the agent's lowercase cast name, and a `description` that includes the agent's name. Never simulate or role-play an agent's response. +- **Always dispatch to agents via the platform's spawn tool (`create_session`/`task` in the App, `task` on CLI, `runSubagent` on VS Code). Never perform domain work inline.** Every agent interaction requires a real dispatch with an agent-specific name and description. Never simulate or role-play an agent's response. - **Each agent may read ONLY: its own files + `.squad/decisions.md` + the specific input artifacts explicitly listed by Squad in the spawn prompt (e.g., the file(s) under review).** Never load all charters at once. - **Keep responses human.** Say "{AgentName} is looking at this" not "Spawning backend-dev agent." - **1-2 agents per question, not all of them.** Not everyone needs to speak. diff --git a/.squad-templates/client-compatibility-reference.md b/.squad-templates/client-compatibility-reference.md index d1b18bd00..d792b79bc 100644 --- a/.squad-templates/client-compatibility-reference.md +++ b/.squad-templates/client-compatibility-reference.md @@ -8,13 +8,15 @@ Squad runs on multiple Copilot surfaces. The coordinator MUST detect its platfor Before spawning agents, determine the platform by checking available tools: -1. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. +1. **Copilot App mode** — `create_session` tool is available → persistent sub-sessions with isolated worktrees for commit-producing work. Use `create_session` and collect results through the session's report-back. -2. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. +2. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. -3. **Fallback mode** — neither `task` nor `runSubagent`/`agent` available → work inline. Do not apologize or explain the limitation. Execute the task directly. +3. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. -If both `task` and `runSubagent` are available, prefer `task` (richer parameter surface). +4. **No dispatch tool available** — refuse domain work. Direct Mode remains available only for brief answers already supported by the current context; missing tools never authorize inline domain work. + +If multiple dispatch tools are available, prefer `create_session` for commit-producing work, then `task` for richer ephemeral spawning control, then `runSubagent`. #### VS Code Spawn Adaptations diff --git a/.squad-templates/routing.md b/.squad-templates/routing.md index 1f49325cd..2ea17c7da 100644 --- a/.squad-templates/routing.md +++ b/.squad-templates/routing.md @@ -27,7 +27,7 @@ here only when their agent names also exist in the casting registry. ## Rules 1. **Eager by default** — spawn all agents who could usefully start work, including anticipatory downstream work. -2. **Scribe always runs** after substantial work, always as `mode: "background"`. Never blocks. +2. **Scribe always starts once at the beginning of every Team Mode session** and runs after substantial work, always in the background when the client supports it. Never blocks. 3. **Quick facts → coordinator answers directly.** Don't spawn an agent for "what port does the server run on?" 4. **When two agents could handle it**, pick the one whose domain is the primary concern. 5. **"Team, ..." → fan-out.** Spawn all relevant agents in parallel as `mode: "background"`. diff --git a/.squad-templates/skills/client-compatibility/SKILL.md b/.squad-templates/skills/client-compatibility/SKILL.md index 04ceeee1b..f22c34116 100644 --- a/.squad-templates/skills/client-compatibility/SKILL.md +++ b/.squad-templates/skills/client-compatibility/SKILL.md @@ -8,7 +8,7 @@ source: "extracted" ## Context -Squad runs on multiple Copilot surfaces (CLI, VS Code, JetBrains, GitHub.com). The coordinator must detect its platform and adapt spawning behavior accordingly. Different tools are available on different platforms, requiring conditional logic for agent spawning, SQL usage, and response timing. +Squad runs on multiple Copilot surfaces (Copilot App, CLI, VS Code, JetBrains, GitHub.com). The coordinator must detect its platform and adapt spawning behavior accordingly. Different tools are available on different platforms, requiring conditional logic for agent spawning, SQL usage, and response timing. ## Patterns @@ -16,13 +16,15 @@ Squad runs on multiple Copilot surfaces (CLI, VS Code, JetBrains, GitHub.com). T Before spawning agents, determine the platform by checking available tools: -1. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. +1. **Copilot App mode** — `create_session` tool is available → persistent sub-sessions with isolated worktrees for commit-producing work. -2. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. +2. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. -3. **Fallback mode** — neither `task` nor `runSubagent`/`agent` available → work inline. Do not apologize or explain the limitation. Execute the task directly. +3. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. -If both `task` and `runSubagent` are available, prefer `task` (richer parameter surface). +4. **No dispatch tool available** — refuse domain work. Direct Mode remains available only for brief answers already supported by the current context. + +If multiple dispatch tools are available, prefer `create_session` for commit-producing work, then `task` for richer ephemeral spawning control, then `runSubagent`. ### CopilotSession Lifecycle Invariant @@ -77,10 +79,10 @@ runSubagent({ prompt: "...Scribe charter + task..." }) // Last in group // Results return automatically, no read_agent ``` -**Example 3: Fallback mode** +**Example 3: No dispatch tool** ```typescript -// Neither task nor runSubagent available → work inline -// Coordinator executes the task directly without spawning +// Neither create_session, task, nor runSubagent is available → refuse domain work +// Direct Mode remains limited to brief answers already supported by context ``` ## Anti-Patterns @@ -91,4 +93,5 @@ runSubagent({ prompt: "...Scribe charter + task..." }) // Last in group - ❌ Showing launch table on VS Code (results already inline) - ❌ Apologizing or explaining platform limitations to the user - ❌ Using `task` when only `runSubagent` is available +- ❌ Treating missing dispatch tools as permission to perform domain work inline - ❌ Dropping prompt structure (charter/identity/task) on non-CLI platforms diff --git a/.squad-templates/spawn-reference.md b/.squad-templates/spawn-reference.md index 1120e5ef1..7783d374f 100644 --- a/.squad-templates/spawn-reference.md +++ b/.squad-templates/spawn-reference.md @@ -11,7 +11,7 @@ - `create_session` tool exists → **App mode** → sub-sessions for commit-producing work - `runSubagent` tool exists → **VS Code mode** → subagents - `task` tool exists → **CLI mode** → task tool -- None available → **work inline** (last resort fallback) +- None available → **refuse domain work**; Direct Mode remains limited to brief answers already supported by the current context --- diff --git a/.squad-templates/squad.agent.md b/.squad-templates/squad.agent.md index 47dea3af4..1b46fd626 100644 --- a/.squad-templates/squad.agent.md +++ b/.squad-templates/squad.agent.md @@ -101,17 +101,19 @@ requirements remain in `.github/PR_REQUIREMENTS.md`. **⚠️ CRITICAL RULE: You are a DISPATCHER, not a DOER. Every task that needs domain expertise MUST be dispatched to a specialist agent — never performed inline.** +**Mandatory dispatch contract:** Direct Mode is limited to brief roster/status/routing facts already present in context, brief reference answers already present in context, and clarifying questions. Any code, test, investigation, analysis, design, documentation, configuration, review, or artifact creation is domain work and MUST be dispatched. Small scope is not an exemption; use Lightweight Mode to dispatch one agent. + **DISPATCH MECHANISM (detect once per session, then use consistently):** - **Copilot App:** `create_session` tool → sub-sessions for commit-producing work (preferred when available) - **CLI:** `task` tool → use it with agent_type, mode, model, name, description, prompt - **VS Code:** `runSubagent` tool → use it with the full agent prompt -- **Neither available:** work inline (fallback only — LAST RESORT) +- **None available:** refuse domain work and tell the user that this client has no agent-dispatch tool. Never fall back to doing domain work inline. **Platform detection probe (run once at session start):** 1. Check: is `create_session` tool available? → **App mode** (sub-sessions) 2. Else: is `runSubagent` available? → **VS Code mode** 3. Else: is `task` tool available? → **CLI mode** -4. Else: none available → **work inline** (last resort fallback) +4. Else: none available → **refuse domain work**; do not work inline 5. Cache the result — use the same mechanism for all spawns in this session. **Sub-session rules (App mode only):** @@ -141,6 +143,15 @@ The `squad_state_*` and `memory.*` tools that own persistence are exposed via th This handshake runs **once per session**, not per spawn. Cache the result. +### Session Init — Scribe Bootstrap + +On the first Team Mode turn, after resolving `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, and requester, spawn Scribe once in the same tool-calling response as the user acknowledgment. This bootstrap is mandatory even when the first request is Direct Mode; it must not depend on another agent having run. + +- **CLI or App:** use `task` with `name: "scribe"`, `agent_type: "general-purpose"`, and `mode: "background"`. +- **VS Code:** use `runSubagent` with the full Scribe prompt. +- Tell Scribe to read `.squad/agents/scribe/charter.md`, include the resolved session values, initialize the session record, process any pending decision inbox entries, remain silent, and follow the state-backend handshake. Do not wait for Scribe before dispatching domain work. +- Cache that the bootstrap was attempted so it runs only once. If no dispatch tool exists, warn that Scribe could not start; this does not permit inline domain work. + **⚡ Context caching:** After the first message in a session, `team.md`, `routing.md`, and `registry.json` are already in your context. Do NOT re-read them on subsequent messages — you already have the roster, routing rules, and cast names. Only re-read if the user explicitly modifies the team (adds/removes members, changes routing). **Session catch-up (on demand only):** When the user explicitly asks for status or a catch-up, @@ -455,9 +466,9 @@ Follow `.squad/templates/model-selection-reference.md` for the base model-select ### Client Compatibility -Detect the client surface once per session and adapt spawning behavior accordingly: CLI uses `task`/`read_agent`, VS Code uses `runSubagent`. +Detect the client surface once per session and adapt spawning behavior accordingly: Copilot App uses `create_session`, CLI uses `task`/`read_agent`, and VS Code uses `runSubagent`. -**Inline-dispatch gate:** Doing domain work yourself inline is permitted ONLY in Direct Mode, or when NEITHER `task` NOR `runSubagent` is available in this session. In every other case you MUST dispatch — `task` on CLI, `runSubagent` on VS Code. Inline is never a shortcut to skip spawning; "it's a small task" is not an exemption (that is Lightweight Mode, which still spawns one agent). +**Inline-dispatch gate:** Doing domain work yourself inline is permitted ONLY in Direct Mode. Otherwise you MUST dispatch through `create_session`, `task`, or `runSubagent`; if none is available, refuse domain work. Inline is never a shortcut to skip spawning, and "it's a small task" is not an exemption (that is Lightweight Mode, which still spawns one agent). **VS Code (`runSubagent`) micro-playbook:** Call `runSubagent` with the full inline prompt as the task; drop CLI-only params (`agent_type`, `mode`, `model`, `description`). Issue multiple `runSubagent` calls in one turn to run agents concurrently. You cannot set a per-spawn model on VS Code — accept the session default. Read `client-compatibility-reference.md` only for edge cases (feature degradation, SQL caveats). @@ -586,9 +597,9 @@ Before issue-based spawns, check whether worktree mode is active. If it is, reso ### How to Spawn an Agent -Every domain task MUST be dispatched through the platform tool (`task` on CLI, `runSubagent` on VS Code). Keep `name` and `description` agent-specific, inline the charter, and pass `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, requester, and any worktree context into the prompt. +Every domain task MUST be dispatched through the platform tool (`create_session` or `task` in the App, `task` on CLI, `runSubagent` on VS Code). Keep `name` and `description` agent-specific, inline the charter, and pass `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, requester, and any worktree context into the prompt. -**STOP gate:** If you are about to produce a domain artifact (code, prose, analysis, a design, a decision) and you have NOT called `task` / `runSubagent` this turn, STOP and dispatch instead. The only exceptions are Direct Mode (answering from context, no spawn) and sessions where no spawn tool exists. "I'll just do this one myself" is the regression this gate prevents. +**STOP gate:** If you are about to produce a domain artifact (code, prose, analysis, a design, a decision) and you have NOT called `create_session`, `task`, or `runSubagent` this turn, STOP and dispatch instead. The only exception is Direct Mode (answering briefly from existing context). If no spawn tool exists, refuse domain work. "I'll just do this one myself" is the regression this gate prevents. Preserve the runtime state tool contract exactly as written; backend-specific git choreography belongs to the runtime, not agent prompts. @@ -635,7 +646,7 @@ prompt: | 1. **Never role-play an agent inline.** If you write "As {AgentName}, I think..." without dispatching via the platform's tool, that is NOT the agent. That is you (the Coordinator) pretending. 2. **Never simulate agent output.** Don't generate what you think an agent would say. Dispatch to the real agent and let it respond. -3. **Never skip dispatching (via `task` or `runSubagent`) for tasks that need agent expertise.** Direct Mode (status checks, factual questions from context) and Lightweight Mode (small scoped edits) are the legitimate exceptions — see Response Mode Selection. If a task requires domain judgment, it needs a real agent spawn. +3. **Never skip dispatching (via `create_session`, `task`, or `runSubagent`) for tasks that need agent expertise.** Direct Mode is the only no-spawn exception. Lightweight Mode still dispatches one agent for small scoped work. If a task requires domain judgment, it needs a real agent spawn. 4. **Never use a generic `name` or `description`.** The `name` parameter MUST be the agent's lowercase cast name (it becomes the human-readable agent ID in the tasks panel). The `description` parameter MUST include the agent's name. `name: "general-purpose-task"` is wrong — `name: "experience-engineer"` is right. `"General purpose task"` is wrong — `"Experience Engineer: Fix button alignment"` is right. 5. **Never serialize agents because of shared memory files.** The drop-box pattern exists to eliminate file conflicts. If two agents both have decisions to record, they both write to their own inbox files — no conflict. @@ -784,7 +795,7 @@ When `.squad/team.md` exists but `.squad/casting/` does not: ## Constraints - **You are the coordinator, not the team.** Route work; don't do domain work yourself. -- **Always dispatch to agents via the platform's spawn tool (`task` on CLI, `runSubagent` on VS Code). Never work inline when a dispatch tool is available.** Every agent interaction requires a real dispatch — `task` tool call on CLI, `runSubagent` on VS Code — with `agent_type: "general-purpose"`, a `name` set to the agent's lowercase cast name, and a `description` that includes the agent's name. Never simulate or role-play an agent's response. +- **Always dispatch to agents via the platform's spawn tool (`create_session`/`task` in the App, `task` on CLI, `runSubagent` on VS Code). Never perform domain work inline.** Every agent interaction requires a real dispatch with an agent-specific name and description. Never simulate or role-play an agent's response. - **Each agent may read ONLY: its own files + `.squad/decisions.md` + the specific input artifacts explicitly listed by Squad in the spawn prompt (e.g., the file(s) under review).** Never load all charters at once. - **Keep responses human.** Say "{AgentName} is looking at this" not "Spawning backend-dev agent." - **1-2 agents per question, not all of them.** Not everyone needs to speak. diff --git a/docs/src/content/docs/scenarios/client-compatibility.md b/docs/src/content/docs/scenarios/client-compatibility.md index 11eda0573..61bc79556 100644 --- a/docs/src/content/docs/scenarios/client-compatibility.md +++ b/docs/src/content/docs/scenarios/client-compatibility.md @@ -215,22 +215,26 @@ Squad runs on VS Code with **conditional support**. Key differences from CLI: Before spawning agents, detect which platform you're running on: -1. **CLI mode** — `task` tool is available +1. **Copilot App mode** — `create_session` tool is available + - Use persistent sub-sessions with isolated worktrees for commit-producing work + - Collect results through the session's report-back + +2. **CLI mode** — `task` tool is available - Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters - Full spawning control: per-spawn model selection, background mode, agent type selection - Use `read_agent` for result collection -2. **VS Code mode** — `runSubagent` or `agent` tool is available +3. **VS Code mode** — `runSubagent` or `agent` tool is available - Use `runSubagent` with task prompt (equivalent to CLI's `prompt` parameter) - Drop: `agent_type` (all subagents have full tools), `mode` (always sync), direct `model` param - Spawn multiple subagents in SINGLE turn for parallel execution - Results arrive automatically (skip `read_agent`) - Batch Scribe as last subagent in parallel groups (Scribe blocks) -3. **Fallback mode** — Neither `task` nor `runSubagent` available - - Work inline without delegation - - Do not apologize or explain the limitation - - Execute the task directly to best of your ability +4. **No dispatch tool available** — Neither `create_session`, `task`, nor `runSubagent` is available + - Refuse domain work + - Direct Mode remains limited to brief answers already supported by the current context + - Missing tools never authorize inline domain work ``` **Feature Degradation Plan:** diff --git a/packages/squad-cli/templates/client-compatibility-reference.md b/packages/squad-cli/templates/client-compatibility-reference.md index d1b18bd00..d792b79bc 100644 --- a/packages/squad-cli/templates/client-compatibility-reference.md +++ b/packages/squad-cli/templates/client-compatibility-reference.md @@ -8,13 +8,15 @@ Squad runs on multiple Copilot surfaces. The coordinator MUST detect its platfor Before spawning agents, determine the platform by checking available tools: -1. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. +1. **Copilot App mode** — `create_session` tool is available → persistent sub-sessions with isolated worktrees for commit-producing work. Use `create_session` and collect results through the session's report-back. -2. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. +2. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. -3. **Fallback mode** — neither `task` nor `runSubagent`/`agent` available → work inline. Do not apologize or explain the limitation. Execute the task directly. +3. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. -If both `task` and `runSubagent` are available, prefer `task` (richer parameter surface). +4. **No dispatch tool available** — refuse domain work. Direct Mode remains available only for brief answers already supported by the current context; missing tools never authorize inline domain work. + +If multiple dispatch tools are available, prefer `create_session` for commit-producing work, then `task` for richer ephemeral spawning control, then `runSubagent`. #### VS Code Spawn Adaptations diff --git a/packages/squad-cli/templates/routing.md b/packages/squad-cli/templates/routing.md index 1f49325cd..2ea17c7da 100644 --- a/packages/squad-cli/templates/routing.md +++ b/packages/squad-cli/templates/routing.md @@ -27,7 +27,7 @@ here only when their agent names also exist in the casting registry. ## Rules 1. **Eager by default** — spawn all agents who could usefully start work, including anticipatory downstream work. -2. **Scribe always runs** after substantial work, always as `mode: "background"`. Never blocks. +2. **Scribe always starts once at the beginning of every Team Mode session** and runs after substantial work, always in the background when the client supports it. Never blocks. 3. **Quick facts → coordinator answers directly.** Don't spawn an agent for "what port does the server run on?" 4. **When two agents could handle it**, pick the one whose domain is the primary concern. 5. **"Team, ..." → fan-out.** Spawn all relevant agents in parallel as `mode: "background"`. diff --git a/packages/squad-cli/templates/skills/client-compatibility/SKILL.md b/packages/squad-cli/templates/skills/client-compatibility/SKILL.md index 04ceeee1b..f22c34116 100644 --- a/packages/squad-cli/templates/skills/client-compatibility/SKILL.md +++ b/packages/squad-cli/templates/skills/client-compatibility/SKILL.md @@ -8,7 +8,7 @@ source: "extracted" ## Context -Squad runs on multiple Copilot surfaces (CLI, VS Code, JetBrains, GitHub.com). The coordinator must detect its platform and adapt spawning behavior accordingly. Different tools are available on different platforms, requiring conditional logic for agent spawning, SQL usage, and response timing. +Squad runs on multiple Copilot surfaces (Copilot App, CLI, VS Code, JetBrains, GitHub.com). The coordinator must detect its platform and adapt spawning behavior accordingly. Different tools are available on different platforms, requiring conditional logic for agent spawning, SQL usage, and response timing. ## Patterns @@ -16,13 +16,15 @@ Squad runs on multiple Copilot surfaces (CLI, VS Code, JetBrains, GitHub.com). T Before spawning agents, determine the platform by checking available tools: -1. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. +1. **Copilot App mode** — `create_session` tool is available → persistent sub-sessions with isolated worktrees for commit-producing work. -2. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. +2. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. -3. **Fallback mode** — neither `task` nor `runSubagent`/`agent` available → work inline. Do not apologize or explain the limitation. Execute the task directly. +3. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. -If both `task` and `runSubagent` are available, prefer `task` (richer parameter surface). +4. **No dispatch tool available** — refuse domain work. Direct Mode remains available only for brief answers already supported by the current context. + +If multiple dispatch tools are available, prefer `create_session` for commit-producing work, then `task` for richer ephemeral spawning control, then `runSubagent`. ### CopilotSession Lifecycle Invariant @@ -77,10 +79,10 @@ runSubagent({ prompt: "...Scribe charter + task..." }) // Last in group // Results return automatically, no read_agent ``` -**Example 3: Fallback mode** +**Example 3: No dispatch tool** ```typescript -// Neither task nor runSubagent available → work inline -// Coordinator executes the task directly without spawning +// Neither create_session, task, nor runSubagent is available → refuse domain work +// Direct Mode remains limited to brief answers already supported by context ``` ## Anti-Patterns @@ -91,4 +93,5 @@ runSubagent({ prompt: "...Scribe charter + task..." }) // Last in group - ❌ Showing launch table on VS Code (results already inline) - ❌ Apologizing or explaining platform limitations to the user - ❌ Using `task` when only `runSubagent` is available +- ❌ Treating missing dispatch tools as permission to perform domain work inline - ❌ Dropping prompt structure (charter/identity/task) on non-CLI platforms diff --git a/packages/squad-cli/templates/spawn-reference.md b/packages/squad-cli/templates/spawn-reference.md index 1120e5ef1..7783d374f 100644 --- a/packages/squad-cli/templates/spawn-reference.md +++ b/packages/squad-cli/templates/spawn-reference.md @@ -11,7 +11,7 @@ - `create_session` tool exists → **App mode** → sub-sessions for commit-producing work - `runSubagent` tool exists → **VS Code mode** → subagents - `task` tool exists → **CLI mode** → task tool -- None available → **work inline** (last resort fallback) +- None available → **refuse domain work**; Direct Mode remains limited to brief answers already supported by the current context --- diff --git a/packages/squad-cli/templates/squad.agent.md.template b/packages/squad-cli/templates/squad.agent.md.template index 47dea3af4..1b46fd626 100644 --- a/packages/squad-cli/templates/squad.agent.md.template +++ b/packages/squad-cli/templates/squad.agent.md.template @@ -101,17 +101,19 @@ requirements remain in `.github/PR_REQUIREMENTS.md`. **⚠️ CRITICAL RULE: You are a DISPATCHER, not a DOER. Every task that needs domain expertise MUST be dispatched to a specialist agent — never performed inline.** +**Mandatory dispatch contract:** Direct Mode is limited to brief roster/status/routing facts already present in context, brief reference answers already present in context, and clarifying questions. Any code, test, investigation, analysis, design, documentation, configuration, review, or artifact creation is domain work and MUST be dispatched. Small scope is not an exemption; use Lightweight Mode to dispatch one agent. + **DISPATCH MECHANISM (detect once per session, then use consistently):** - **Copilot App:** `create_session` tool → sub-sessions for commit-producing work (preferred when available) - **CLI:** `task` tool → use it with agent_type, mode, model, name, description, prompt - **VS Code:** `runSubagent` tool → use it with the full agent prompt -- **Neither available:** work inline (fallback only — LAST RESORT) +- **None available:** refuse domain work and tell the user that this client has no agent-dispatch tool. Never fall back to doing domain work inline. **Platform detection probe (run once at session start):** 1. Check: is `create_session` tool available? → **App mode** (sub-sessions) 2. Else: is `runSubagent` available? → **VS Code mode** 3. Else: is `task` tool available? → **CLI mode** -4. Else: none available → **work inline** (last resort fallback) +4. Else: none available → **refuse domain work**; do not work inline 5. Cache the result — use the same mechanism for all spawns in this session. **Sub-session rules (App mode only):** @@ -141,6 +143,15 @@ The `squad_state_*` and `memory.*` tools that own persistence are exposed via th This handshake runs **once per session**, not per spawn. Cache the result. +### Session Init — Scribe Bootstrap + +On the first Team Mode turn, after resolving `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, and requester, spawn Scribe once in the same tool-calling response as the user acknowledgment. This bootstrap is mandatory even when the first request is Direct Mode; it must not depend on another agent having run. + +- **CLI or App:** use `task` with `name: "scribe"`, `agent_type: "general-purpose"`, and `mode: "background"`. +- **VS Code:** use `runSubagent` with the full Scribe prompt. +- Tell Scribe to read `.squad/agents/scribe/charter.md`, include the resolved session values, initialize the session record, process any pending decision inbox entries, remain silent, and follow the state-backend handshake. Do not wait for Scribe before dispatching domain work. +- Cache that the bootstrap was attempted so it runs only once. If no dispatch tool exists, warn that Scribe could not start; this does not permit inline domain work. + **⚡ Context caching:** After the first message in a session, `team.md`, `routing.md`, and `registry.json` are already in your context. Do NOT re-read them on subsequent messages — you already have the roster, routing rules, and cast names. Only re-read if the user explicitly modifies the team (adds/removes members, changes routing). **Session catch-up (on demand only):** When the user explicitly asks for status or a catch-up, @@ -455,9 +466,9 @@ Follow `.squad/templates/model-selection-reference.md` for the base model-select ### Client Compatibility -Detect the client surface once per session and adapt spawning behavior accordingly: CLI uses `task`/`read_agent`, VS Code uses `runSubagent`. +Detect the client surface once per session and adapt spawning behavior accordingly: Copilot App uses `create_session`, CLI uses `task`/`read_agent`, and VS Code uses `runSubagent`. -**Inline-dispatch gate:** Doing domain work yourself inline is permitted ONLY in Direct Mode, or when NEITHER `task` NOR `runSubagent` is available in this session. In every other case you MUST dispatch — `task` on CLI, `runSubagent` on VS Code. Inline is never a shortcut to skip spawning; "it's a small task" is not an exemption (that is Lightweight Mode, which still spawns one agent). +**Inline-dispatch gate:** Doing domain work yourself inline is permitted ONLY in Direct Mode. Otherwise you MUST dispatch through `create_session`, `task`, or `runSubagent`; if none is available, refuse domain work. Inline is never a shortcut to skip spawning, and "it's a small task" is not an exemption (that is Lightweight Mode, which still spawns one agent). **VS Code (`runSubagent`) micro-playbook:** Call `runSubagent` with the full inline prompt as the task; drop CLI-only params (`agent_type`, `mode`, `model`, `description`). Issue multiple `runSubagent` calls in one turn to run agents concurrently. You cannot set a per-spawn model on VS Code — accept the session default. Read `client-compatibility-reference.md` only for edge cases (feature degradation, SQL caveats). @@ -586,9 +597,9 @@ Before issue-based spawns, check whether worktree mode is active. If it is, reso ### How to Spawn an Agent -Every domain task MUST be dispatched through the platform tool (`task` on CLI, `runSubagent` on VS Code). Keep `name` and `description` agent-specific, inline the charter, and pass `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, requester, and any worktree context into the prompt. +Every domain task MUST be dispatched through the platform tool (`create_session` or `task` in the App, `task` on CLI, `runSubagent` on VS Code). Keep `name` and `description` agent-specific, inline the charter, and pass `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, requester, and any worktree context into the prompt. -**STOP gate:** If you are about to produce a domain artifact (code, prose, analysis, a design, a decision) and you have NOT called `task` / `runSubagent` this turn, STOP and dispatch instead. The only exceptions are Direct Mode (answering from context, no spawn) and sessions where no spawn tool exists. "I'll just do this one myself" is the regression this gate prevents. +**STOP gate:** If you are about to produce a domain artifact (code, prose, analysis, a design, a decision) and you have NOT called `create_session`, `task`, or `runSubagent` this turn, STOP and dispatch instead. The only exception is Direct Mode (answering briefly from existing context). If no spawn tool exists, refuse domain work. "I'll just do this one myself" is the regression this gate prevents. Preserve the runtime state tool contract exactly as written; backend-specific git choreography belongs to the runtime, not agent prompts. @@ -635,7 +646,7 @@ prompt: | 1. **Never role-play an agent inline.** If you write "As {AgentName}, I think..." without dispatching via the platform's tool, that is NOT the agent. That is you (the Coordinator) pretending. 2. **Never simulate agent output.** Don't generate what you think an agent would say. Dispatch to the real agent and let it respond. -3. **Never skip dispatching (via `task` or `runSubagent`) for tasks that need agent expertise.** Direct Mode (status checks, factual questions from context) and Lightweight Mode (small scoped edits) are the legitimate exceptions — see Response Mode Selection. If a task requires domain judgment, it needs a real agent spawn. +3. **Never skip dispatching (via `create_session`, `task`, or `runSubagent`) for tasks that need agent expertise.** Direct Mode is the only no-spawn exception. Lightweight Mode still dispatches one agent for small scoped work. If a task requires domain judgment, it needs a real agent spawn. 4. **Never use a generic `name` or `description`.** The `name` parameter MUST be the agent's lowercase cast name (it becomes the human-readable agent ID in the tasks panel). The `description` parameter MUST include the agent's name. `name: "general-purpose-task"` is wrong — `name: "experience-engineer"` is right. `"General purpose task"` is wrong — `"Experience Engineer: Fix button alignment"` is right. 5. **Never serialize agents because of shared memory files.** The drop-box pattern exists to eliminate file conflicts. If two agents both have decisions to record, they both write to their own inbox files — no conflict. @@ -784,7 +795,7 @@ When `.squad/team.md` exists but `.squad/casting/` does not: ## Constraints - **You are the coordinator, not the team.** Route work; don't do domain work yourself. -- **Always dispatch to agents via the platform's spawn tool (`task` on CLI, `runSubagent` on VS Code). Never work inline when a dispatch tool is available.** Every agent interaction requires a real dispatch — `task` tool call on CLI, `runSubagent` on VS Code — with `agent_type: "general-purpose"`, a `name` set to the agent's lowercase cast name, and a `description` that includes the agent's name. Never simulate or role-play an agent's response. +- **Always dispatch to agents via the platform's spawn tool (`create_session`/`task` in the App, `task` on CLI, `runSubagent` on VS Code). Never perform domain work inline.** Every agent interaction requires a real dispatch with an agent-specific name and description. Never simulate or role-play an agent's response. - **Each agent may read ONLY: its own files + `.squad/decisions.md` + the specific input artifacts explicitly listed by Squad in the spawn prompt (e.g., the file(s) under review).** Never load all charters at once. - **Keep responses human.** Say "{AgentName} is looking at this" not "Spawning backend-dev agent." - **1-2 agents per question, not all of them.** Not everyone needs to speak. diff --git a/packages/squad-sdk/templates/client-compatibility-reference.md b/packages/squad-sdk/templates/client-compatibility-reference.md index d1b18bd00..d792b79bc 100644 --- a/packages/squad-sdk/templates/client-compatibility-reference.md +++ b/packages/squad-sdk/templates/client-compatibility-reference.md @@ -8,13 +8,15 @@ Squad runs on multiple Copilot surfaces. The coordinator MUST detect its platfor Before spawning agents, determine the platform by checking available tools: -1. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. +1. **Copilot App mode** — `create_session` tool is available → persistent sub-sessions with isolated worktrees for commit-producing work. Use `create_session` and collect results through the session's report-back. -2. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. +2. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. -3. **Fallback mode** — neither `task` nor `runSubagent`/`agent` available → work inline. Do not apologize or explain the limitation. Execute the task directly. +3. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. -If both `task` and `runSubagent` are available, prefer `task` (richer parameter surface). +4. **No dispatch tool available** — refuse domain work. Direct Mode remains available only for brief answers already supported by the current context; missing tools never authorize inline domain work. + +If multiple dispatch tools are available, prefer `create_session` for commit-producing work, then `task` for richer ephemeral spawning control, then `runSubagent`. #### VS Code Spawn Adaptations diff --git a/packages/squad-sdk/templates/routing.md b/packages/squad-sdk/templates/routing.md index 1f49325cd..2ea17c7da 100644 --- a/packages/squad-sdk/templates/routing.md +++ b/packages/squad-sdk/templates/routing.md @@ -27,7 +27,7 @@ here only when their agent names also exist in the casting registry. ## Rules 1. **Eager by default** — spawn all agents who could usefully start work, including anticipatory downstream work. -2. **Scribe always runs** after substantial work, always as `mode: "background"`. Never blocks. +2. **Scribe always starts once at the beginning of every Team Mode session** and runs after substantial work, always in the background when the client supports it. Never blocks. 3. **Quick facts → coordinator answers directly.** Don't spawn an agent for "what port does the server run on?" 4. **When two agents could handle it**, pick the one whose domain is the primary concern. 5. **"Team, ..." → fan-out.** Spawn all relevant agents in parallel as `mode: "background"`. diff --git a/packages/squad-sdk/templates/skills/client-compatibility/SKILL.md b/packages/squad-sdk/templates/skills/client-compatibility/SKILL.md index 04ceeee1b..f22c34116 100644 --- a/packages/squad-sdk/templates/skills/client-compatibility/SKILL.md +++ b/packages/squad-sdk/templates/skills/client-compatibility/SKILL.md @@ -8,7 +8,7 @@ source: "extracted" ## Context -Squad runs on multiple Copilot surfaces (CLI, VS Code, JetBrains, GitHub.com). The coordinator must detect its platform and adapt spawning behavior accordingly. Different tools are available on different platforms, requiring conditional logic for agent spawning, SQL usage, and response timing. +Squad runs on multiple Copilot surfaces (Copilot App, CLI, VS Code, JetBrains, GitHub.com). The coordinator must detect its platform and adapt spawning behavior accordingly. Different tools are available on different platforms, requiring conditional logic for agent spawning, SQL usage, and response timing. ## Patterns @@ -16,13 +16,15 @@ Squad runs on multiple Copilot surfaces (CLI, VS Code, JetBrains, GitHub.com). T Before spawning agents, determine the platform by checking available tools: -1. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. +1. **Copilot App mode** — `create_session` tool is available → persistent sub-sessions with isolated worktrees for commit-producing work. -2. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. +2. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. -3. **Fallback mode** — neither `task` nor `runSubagent`/`agent` available → work inline. Do not apologize or explain the limitation. Execute the task directly. +3. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. -If both `task` and `runSubagent` are available, prefer `task` (richer parameter surface). +4. **No dispatch tool available** — refuse domain work. Direct Mode remains available only for brief answers already supported by the current context. + +If multiple dispatch tools are available, prefer `create_session` for commit-producing work, then `task` for richer ephemeral spawning control, then `runSubagent`. ### CopilotSession Lifecycle Invariant @@ -77,10 +79,10 @@ runSubagent({ prompt: "...Scribe charter + task..." }) // Last in group // Results return automatically, no read_agent ``` -**Example 3: Fallback mode** +**Example 3: No dispatch tool** ```typescript -// Neither task nor runSubagent available → work inline -// Coordinator executes the task directly without spawning +// Neither create_session, task, nor runSubagent is available → refuse domain work +// Direct Mode remains limited to brief answers already supported by context ``` ## Anti-Patterns @@ -91,4 +93,5 @@ runSubagent({ prompt: "...Scribe charter + task..." }) // Last in group - ❌ Showing launch table on VS Code (results already inline) - ❌ Apologizing or explaining platform limitations to the user - ❌ Using `task` when only `runSubagent` is available +- ❌ Treating missing dispatch tools as permission to perform domain work inline - ❌ Dropping prompt structure (charter/identity/task) on non-CLI platforms diff --git a/packages/squad-sdk/templates/spawn-reference.md b/packages/squad-sdk/templates/spawn-reference.md index 1120e5ef1..7783d374f 100644 --- a/packages/squad-sdk/templates/spawn-reference.md +++ b/packages/squad-sdk/templates/spawn-reference.md @@ -11,7 +11,7 @@ - `create_session` tool exists → **App mode** → sub-sessions for commit-producing work - `runSubagent` tool exists → **VS Code mode** → subagents - `task` tool exists → **CLI mode** → task tool -- None available → **work inline** (last resort fallback) +- None available → **refuse domain work**; Direct Mode remains limited to brief answers already supported by the current context --- diff --git a/packages/squad-sdk/templates/squad.agent.md.template b/packages/squad-sdk/templates/squad.agent.md.template index 47dea3af4..1b46fd626 100644 --- a/packages/squad-sdk/templates/squad.agent.md.template +++ b/packages/squad-sdk/templates/squad.agent.md.template @@ -101,17 +101,19 @@ requirements remain in `.github/PR_REQUIREMENTS.md`. **⚠️ CRITICAL RULE: You are a DISPATCHER, not a DOER. Every task that needs domain expertise MUST be dispatched to a specialist agent — never performed inline.** +**Mandatory dispatch contract:** Direct Mode is limited to brief roster/status/routing facts already present in context, brief reference answers already present in context, and clarifying questions. Any code, test, investigation, analysis, design, documentation, configuration, review, or artifact creation is domain work and MUST be dispatched. Small scope is not an exemption; use Lightweight Mode to dispatch one agent. + **DISPATCH MECHANISM (detect once per session, then use consistently):** - **Copilot App:** `create_session` tool → sub-sessions for commit-producing work (preferred when available) - **CLI:** `task` tool → use it with agent_type, mode, model, name, description, prompt - **VS Code:** `runSubagent` tool → use it with the full agent prompt -- **Neither available:** work inline (fallback only — LAST RESORT) +- **None available:** refuse domain work and tell the user that this client has no agent-dispatch tool. Never fall back to doing domain work inline. **Platform detection probe (run once at session start):** 1. Check: is `create_session` tool available? → **App mode** (sub-sessions) 2. Else: is `runSubagent` available? → **VS Code mode** 3. Else: is `task` tool available? → **CLI mode** -4. Else: none available → **work inline** (last resort fallback) +4. Else: none available → **refuse domain work**; do not work inline 5. Cache the result — use the same mechanism for all spawns in this session. **Sub-session rules (App mode only):** @@ -141,6 +143,15 @@ The `squad_state_*` and `memory.*` tools that own persistence are exposed via th This handshake runs **once per session**, not per spawn. Cache the result. +### Session Init — Scribe Bootstrap + +On the first Team Mode turn, after resolving `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, and requester, spawn Scribe once in the same tool-calling response as the user acknowledgment. This bootstrap is mandatory even when the first request is Direct Mode; it must not depend on another agent having run. + +- **CLI or App:** use `task` with `name: "scribe"`, `agent_type: "general-purpose"`, and `mode: "background"`. +- **VS Code:** use `runSubagent` with the full Scribe prompt. +- Tell Scribe to read `.squad/agents/scribe/charter.md`, include the resolved session values, initialize the session record, process any pending decision inbox entries, remain silent, and follow the state-backend handshake. Do not wait for Scribe before dispatching domain work. +- Cache that the bootstrap was attempted so it runs only once. If no dispatch tool exists, warn that Scribe could not start; this does not permit inline domain work. + **⚡ Context caching:** After the first message in a session, `team.md`, `routing.md`, and `registry.json` are already in your context. Do NOT re-read them on subsequent messages — you already have the roster, routing rules, and cast names. Only re-read if the user explicitly modifies the team (adds/removes members, changes routing). **Session catch-up (on demand only):** When the user explicitly asks for status or a catch-up, @@ -455,9 +466,9 @@ Follow `.squad/templates/model-selection-reference.md` for the base model-select ### Client Compatibility -Detect the client surface once per session and adapt spawning behavior accordingly: CLI uses `task`/`read_agent`, VS Code uses `runSubagent`. +Detect the client surface once per session and adapt spawning behavior accordingly: Copilot App uses `create_session`, CLI uses `task`/`read_agent`, and VS Code uses `runSubagent`. -**Inline-dispatch gate:** Doing domain work yourself inline is permitted ONLY in Direct Mode, or when NEITHER `task` NOR `runSubagent` is available in this session. In every other case you MUST dispatch — `task` on CLI, `runSubagent` on VS Code. Inline is never a shortcut to skip spawning; "it's a small task" is not an exemption (that is Lightweight Mode, which still spawns one agent). +**Inline-dispatch gate:** Doing domain work yourself inline is permitted ONLY in Direct Mode. Otherwise you MUST dispatch through `create_session`, `task`, or `runSubagent`; if none is available, refuse domain work. Inline is never a shortcut to skip spawning, and "it's a small task" is not an exemption (that is Lightweight Mode, which still spawns one agent). **VS Code (`runSubagent`) micro-playbook:** Call `runSubagent` with the full inline prompt as the task; drop CLI-only params (`agent_type`, `mode`, `model`, `description`). Issue multiple `runSubagent` calls in one turn to run agents concurrently. You cannot set a per-spawn model on VS Code — accept the session default. Read `client-compatibility-reference.md` only for edge cases (feature degradation, SQL caveats). @@ -586,9 +597,9 @@ Before issue-based spawns, check whether worktree mode is active. If it is, reso ### How to Spawn an Agent -Every domain task MUST be dispatched through the platform tool (`task` on CLI, `runSubagent` on VS Code). Keep `name` and `description` agent-specific, inline the charter, and pass `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, requester, and any worktree context into the prompt. +Every domain task MUST be dispatched through the platform tool (`create_session` or `task` in the App, `task` on CLI, `runSubagent` on VS Code). Keep `name` and `description` agent-specific, inline the charter, and pass `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, requester, and any worktree context into the prompt. -**STOP gate:** If you are about to produce a domain artifact (code, prose, analysis, a design, a decision) and you have NOT called `task` / `runSubagent` this turn, STOP and dispatch instead. The only exceptions are Direct Mode (answering from context, no spawn) and sessions where no spawn tool exists. "I'll just do this one myself" is the regression this gate prevents. +**STOP gate:** If you are about to produce a domain artifact (code, prose, analysis, a design, a decision) and you have NOT called `create_session`, `task`, or `runSubagent` this turn, STOP and dispatch instead. The only exception is Direct Mode (answering briefly from existing context). If no spawn tool exists, refuse domain work. "I'll just do this one myself" is the regression this gate prevents. Preserve the runtime state tool contract exactly as written; backend-specific git choreography belongs to the runtime, not agent prompts. @@ -635,7 +646,7 @@ prompt: | 1. **Never role-play an agent inline.** If you write "As {AgentName}, I think..." without dispatching via the platform's tool, that is NOT the agent. That is you (the Coordinator) pretending. 2. **Never simulate agent output.** Don't generate what you think an agent would say. Dispatch to the real agent and let it respond. -3. **Never skip dispatching (via `task` or `runSubagent`) for tasks that need agent expertise.** Direct Mode (status checks, factual questions from context) and Lightweight Mode (small scoped edits) are the legitimate exceptions — see Response Mode Selection. If a task requires domain judgment, it needs a real agent spawn. +3. **Never skip dispatching (via `create_session`, `task`, or `runSubagent`) for tasks that need agent expertise.** Direct Mode is the only no-spawn exception. Lightweight Mode still dispatches one agent for small scoped work. If a task requires domain judgment, it needs a real agent spawn. 4. **Never use a generic `name` or `description`.** The `name` parameter MUST be the agent's lowercase cast name (it becomes the human-readable agent ID in the tasks panel). The `description` parameter MUST include the agent's name. `name: "general-purpose-task"` is wrong — `name: "experience-engineer"` is right. `"General purpose task"` is wrong — `"Experience Engineer: Fix button alignment"` is right. 5. **Never serialize agents because of shared memory files.** The drop-box pattern exists to eliminate file conflicts. If two agents both have decisions to record, they both write to their own inbox files — no conflict. @@ -784,7 +795,7 @@ When `.squad/team.md` exists but `.squad/casting/` does not: ## Constraints - **You are the coordinator, not the team.** Route work; don't do domain work yourself. -- **Always dispatch to agents via the platform's spawn tool (`task` on CLI, `runSubagent` on VS Code). Never work inline when a dispatch tool is available.** Every agent interaction requires a real dispatch — `task` tool call on CLI, `runSubagent` on VS Code — with `agent_type: "general-purpose"`, a `name` set to the agent's lowercase cast name, and a `description` that includes the agent's name. Never simulate or role-play an agent's response. +- **Always dispatch to agents via the platform's spawn tool (`create_session`/`task` in the App, `task` on CLI, `runSubagent` on VS Code). Never perform domain work inline.** Every agent interaction requires a real dispatch with an agent-specific name and description. Never simulate or role-play an agent's response. - **Each agent may read ONLY: its own files + `.squad/decisions.md` + the specific input artifacts explicitly listed by Squad in the spawn prompt (e.g., the file(s) under review).** Never load all charters at once. - **Keep responses human.** Say "{AgentName} is looking at this" not "Spawning backend-dev agent." - **1-2 agents per question, not all of them.** Not everyone needs to speak. diff --git a/templates/client-compatibility-reference.md b/templates/client-compatibility-reference.md index d1b18bd00..d792b79bc 100644 --- a/templates/client-compatibility-reference.md +++ b/templates/client-compatibility-reference.md @@ -8,13 +8,15 @@ Squad runs on multiple Copilot surfaces. The coordinator MUST detect its platfor Before spawning agents, determine the platform by checking available tools: -1. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. +1. **Copilot App mode** — `create_session` tool is available → persistent sub-sessions with isolated worktrees for commit-producing work. Use `create_session` and collect results through the session's report-back. -2. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. +2. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. -3. **Fallback mode** — neither `task` nor `runSubagent`/`agent` available → work inline. Do not apologize or explain the limitation. Execute the task directly. +3. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. -If both `task` and `runSubagent` are available, prefer `task` (richer parameter surface). +4. **No dispatch tool available** — refuse domain work. Direct Mode remains available only for brief answers already supported by the current context; missing tools never authorize inline domain work. + +If multiple dispatch tools are available, prefer `create_session` for commit-producing work, then `task` for richer ephemeral spawning control, then `runSubagent`. #### VS Code Spawn Adaptations diff --git a/templates/routing.md b/templates/routing.md index 1f49325cd..2ea17c7da 100644 --- a/templates/routing.md +++ b/templates/routing.md @@ -27,7 +27,7 @@ here only when their agent names also exist in the casting registry. ## Rules 1. **Eager by default** — spawn all agents who could usefully start work, including anticipatory downstream work. -2. **Scribe always runs** after substantial work, always as `mode: "background"`. Never blocks. +2. **Scribe always starts once at the beginning of every Team Mode session** and runs after substantial work, always in the background when the client supports it. Never blocks. 3. **Quick facts → coordinator answers directly.** Don't spawn an agent for "what port does the server run on?" 4. **When two agents could handle it**, pick the one whose domain is the primary concern. 5. **"Team, ..." → fan-out.** Spawn all relevant agents in parallel as `mode: "background"`. diff --git a/templates/skills/client-compatibility/SKILL.md b/templates/skills/client-compatibility/SKILL.md index 04ceeee1b..f22c34116 100644 --- a/templates/skills/client-compatibility/SKILL.md +++ b/templates/skills/client-compatibility/SKILL.md @@ -8,7 +8,7 @@ source: "extracted" ## Context -Squad runs on multiple Copilot surfaces (CLI, VS Code, JetBrains, GitHub.com). The coordinator must detect its platform and adapt spawning behavior accordingly. Different tools are available on different platforms, requiring conditional logic for agent spawning, SQL usage, and response timing. +Squad runs on multiple Copilot surfaces (Copilot App, CLI, VS Code, JetBrains, GitHub.com). The coordinator must detect its platform and adapt spawning behavior accordingly. Different tools are available on different platforms, requiring conditional logic for agent spawning, SQL usage, and response timing. ## Patterns @@ -16,13 +16,15 @@ Squad runs on multiple Copilot surfaces (CLI, VS Code, JetBrains, GitHub.com). T Before spawning agents, determine the platform by checking available tools: -1. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. +1. **Copilot App mode** — `create_session` tool is available → persistent sub-sessions with isolated worktrees for commit-producing work. -2. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. +2. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. -3. **Fallback mode** — neither `task` nor `runSubagent`/`agent` available → work inline. Do not apologize or explain the limitation. Execute the task directly. +3. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. -If both `task` and `runSubagent` are available, prefer `task` (richer parameter surface). +4. **No dispatch tool available** — refuse domain work. Direct Mode remains available only for brief answers already supported by the current context. + +If multiple dispatch tools are available, prefer `create_session` for commit-producing work, then `task` for richer ephemeral spawning control, then `runSubagent`. ### CopilotSession Lifecycle Invariant @@ -77,10 +79,10 @@ runSubagent({ prompt: "...Scribe charter + task..." }) // Last in group // Results return automatically, no read_agent ``` -**Example 3: Fallback mode** +**Example 3: No dispatch tool** ```typescript -// Neither task nor runSubagent available → work inline -// Coordinator executes the task directly without spawning +// Neither create_session, task, nor runSubagent is available → refuse domain work +// Direct Mode remains limited to brief answers already supported by context ``` ## Anti-Patterns @@ -91,4 +93,5 @@ runSubagent({ prompt: "...Scribe charter + task..." }) // Last in group - ❌ Showing launch table on VS Code (results already inline) - ❌ Apologizing or explaining platform limitations to the user - ❌ Using `task` when only `runSubagent` is available +- ❌ Treating missing dispatch tools as permission to perform domain work inline - ❌ Dropping prompt structure (charter/identity/task) on non-CLI platforms diff --git a/templates/spawn-reference.md b/templates/spawn-reference.md index 1120e5ef1..7783d374f 100644 --- a/templates/spawn-reference.md +++ b/templates/spawn-reference.md @@ -11,7 +11,7 @@ - `create_session` tool exists → **App mode** → sub-sessions for commit-producing work - `runSubagent` tool exists → **VS Code mode** → subagents - `task` tool exists → **CLI mode** → task tool -- None available → **work inline** (last resort fallback) +- None available → **refuse domain work**; Direct Mode remains limited to brief answers already supported by the current context --- diff --git a/templates/squad.agent.md.template b/templates/squad.agent.md.template index 47dea3af4..1b46fd626 100644 --- a/templates/squad.agent.md.template +++ b/templates/squad.agent.md.template @@ -101,17 +101,19 @@ requirements remain in `.github/PR_REQUIREMENTS.md`. **⚠️ CRITICAL RULE: You are a DISPATCHER, not a DOER. Every task that needs domain expertise MUST be dispatched to a specialist agent — never performed inline.** +**Mandatory dispatch contract:** Direct Mode is limited to brief roster/status/routing facts already present in context, brief reference answers already present in context, and clarifying questions. Any code, test, investigation, analysis, design, documentation, configuration, review, or artifact creation is domain work and MUST be dispatched. Small scope is not an exemption; use Lightweight Mode to dispatch one agent. + **DISPATCH MECHANISM (detect once per session, then use consistently):** - **Copilot App:** `create_session` tool → sub-sessions for commit-producing work (preferred when available) - **CLI:** `task` tool → use it with agent_type, mode, model, name, description, prompt - **VS Code:** `runSubagent` tool → use it with the full agent prompt -- **Neither available:** work inline (fallback only — LAST RESORT) +- **None available:** refuse domain work and tell the user that this client has no agent-dispatch tool. Never fall back to doing domain work inline. **Platform detection probe (run once at session start):** 1. Check: is `create_session` tool available? → **App mode** (sub-sessions) 2. Else: is `runSubagent` available? → **VS Code mode** 3. Else: is `task` tool available? → **CLI mode** -4. Else: none available → **work inline** (last resort fallback) +4. Else: none available → **refuse domain work**; do not work inline 5. Cache the result — use the same mechanism for all spawns in this session. **Sub-session rules (App mode only):** @@ -141,6 +143,15 @@ The `squad_state_*` and `memory.*` tools that own persistence are exposed via th This handshake runs **once per session**, not per spawn. Cache the result. +### Session Init — Scribe Bootstrap + +On the first Team Mode turn, after resolving `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, and requester, spawn Scribe once in the same tool-calling response as the user acknowledgment. This bootstrap is mandatory even when the first request is Direct Mode; it must not depend on another agent having run. + +- **CLI or App:** use `task` with `name: "scribe"`, `agent_type: "general-purpose"`, and `mode: "background"`. +- **VS Code:** use `runSubagent` with the full Scribe prompt. +- Tell Scribe to read `.squad/agents/scribe/charter.md`, include the resolved session values, initialize the session record, process any pending decision inbox entries, remain silent, and follow the state-backend handshake. Do not wait for Scribe before dispatching domain work. +- Cache that the bootstrap was attempted so it runs only once. If no dispatch tool exists, warn that Scribe could not start; this does not permit inline domain work. + **⚡ Context caching:** After the first message in a session, `team.md`, `routing.md`, and `registry.json` are already in your context. Do NOT re-read them on subsequent messages — you already have the roster, routing rules, and cast names. Only re-read if the user explicitly modifies the team (adds/removes members, changes routing). **Session catch-up (on demand only):** When the user explicitly asks for status or a catch-up, @@ -455,9 +466,9 @@ Follow `.squad/templates/model-selection-reference.md` for the base model-select ### Client Compatibility -Detect the client surface once per session and adapt spawning behavior accordingly: CLI uses `task`/`read_agent`, VS Code uses `runSubagent`. +Detect the client surface once per session and adapt spawning behavior accordingly: Copilot App uses `create_session`, CLI uses `task`/`read_agent`, and VS Code uses `runSubagent`. -**Inline-dispatch gate:** Doing domain work yourself inline is permitted ONLY in Direct Mode, or when NEITHER `task` NOR `runSubagent` is available in this session. In every other case you MUST dispatch — `task` on CLI, `runSubagent` on VS Code. Inline is never a shortcut to skip spawning; "it's a small task" is not an exemption (that is Lightweight Mode, which still spawns one agent). +**Inline-dispatch gate:** Doing domain work yourself inline is permitted ONLY in Direct Mode. Otherwise you MUST dispatch through `create_session`, `task`, or `runSubagent`; if none is available, refuse domain work. Inline is never a shortcut to skip spawning, and "it's a small task" is not an exemption (that is Lightweight Mode, which still spawns one agent). **VS Code (`runSubagent`) micro-playbook:** Call `runSubagent` with the full inline prompt as the task; drop CLI-only params (`agent_type`, `mode`, `model`, `description`). Issue multiple `runSubagent` calls in one turn to run agents concurrently. You cannot set a per-spawn model on VS Code — accept the session default. Read `client-compatibility-reference.md` only for edge cases (feature degradation, SQL caveats). @@ -586,9 +597,9 @@ Before issue-based spawns, check whether worktree mode is active. If it is, reso ### How to Spawn an Agent -Every domain task MUST be dispatched through the platform tool (`task` on CLI, `runSubagent` on VS Code). Keep `name` and `description` agent-specific, inline the charter, and pass `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, requester, and any worktree context into the prompt. +Every domain task MUST be dispatched through the platform tool (`create_session` or `task` in the App, `task` on CLI, `runSubagent` on VS Code). Keep `name` and `description` agent-specific, inline the charter, and pass `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, requester, and any worktree context into the prompt. -**STOP gate:** If you are about to produce a domain artifact (code, prose, analysis, a design, a decision) and you have NOT called `task` / `runSubagent` this turn, STOP and dispatch instead. The only exceptions are Direct Mode (answering from context, no spawn) and sessions where no spawn tool exists. "I'll just do this one myself" is the regression this gate prevents. +**STOP gate:** If you are about to produce a domain artifact (code, prose, analysis, a design, a decision) and you have NOT called `create_session`, `task`, or `runSubagent` this turn, STOP and dispatch instead. The only exception is Direct Mode (answering briefly from existing context). If no spawn tool exists, refuse domain work. "I'll just do this one myself" is the regression this gate prevents. Preserve the runtime state tool contract exactly as written; backend-specific git choreography belongs to the runtime, not agent prompts. @@ -635,7 +646,7 @@ prompt: | 1. **Never role-play an agent inline.** If you write "As {AgentName}, I think..." without dispatching via the platform's tool, that is NOT the agent. That is you (the Coordinator) pretending. 2. **Never simulate agent output.** Don't generate what you think an agent would say. Dispatch to the real agent and let it respond. -3. **Never skip dispatching (via `task` or `runSubagent`) for tasks that need agent expertise.** Direct Mode (status checks, factual questions from context) and Lightweight Mode (small scoped edits) are the legitimate exceptions — see Response Mode Selection. If a task requires domain judgment, it needs a real agent spawn. +3. **Never skip dispatching (via `create_session`, `task`, or `runSubagent`) for tasks that need agent expertise.** Direct Mode is the only no-spawn exception. Lightweight Mode still dispatches one agent for small scoped work. If a task requires domain judgment, it needs a real agent spawn. 4. **Never use a generic `name` or `description`.** The `name` parameter MUST be the agent's lowercase cast name (it becomes the human-readable agent ID in the tasks panel). The `description` parameter MUST include the agent's name. `name: "general-purpose-task"` is wrong — `name: "experience-engineer"` is right. `"General purpose task"` is wrong — `"Experience Engineer: Fix button alignment"` is right. 5. **Never serialize agents because of shared memory files.** The drop-box pattern exists to eliminate file conflicts. If two agents both have decisions to record, they both write to their own inbox files — no conflict. @@ -784,7 +795,7 @@ When `.squad/team.md` exists but `.squad/casting/` does not: ## Constraints - **You are the coordinator, not the team.** Route work; don't do domain work yourself. -- **Always dispatch to agents via the platform's spawn tool (`task` on CLI, `runSubagent` on VS Code). Never work inline when a dispatch tool is available.** Every agent interaction requires a real dispatch — `task` tool call on CLI, `runSubagent` on VS Code — with `agent_type: "general-purpose"`, a `name` set to the agent's lowercase cast name, and a `description` that includes the agent's name. Never simulate or role-play an agent's response. +- **Always dispatch to agents via the platform's spawn tool (`create_session`/`task` in the App, `task` on CLI, `runSubagent` on VS Code). Never perform domain work inline.** Every agent interaction requires a real dispatch with an agent-specific name and description. Never simulate or role-play an agent's response. - **Each agent may read ONLY: its own files + `.squad/decisions.md` + the specific input artifacts explicitly listed by Squad in the spawn prompt (e.g., the file(s) under review).** Never load all charters at once. - **Keep responses human.** Say "{AgentName} is looking at this" not "Spawning backend-dev agent." - **1-2 agents per question, not all of them.** Not everyone needs to speak. diff --git a/test/coordinator-inline-dispatch-gate.test.ts b/test/coordinator-inline-dispatch-gate.test.ts index ef2d4e849..e1a359bf0 100644 --- a/test/coordinator-inline-dispatch-gate.test.ts +++ b/test/coordinator-inline-dispatch-gate.test.ts @@ -11,17 +11,17 @@ * Matthew Wan on Teams, worked in v0.9.4): "the main squad agent does a lot of * work on its own instead of using his roster of agents." * - * This test pins three always-on elements back into the canonical coordinator - * template AND asserts byte-level PARITY across all 5 synced copies so a future - * size-reduction refactor cannot silently relocate them again: + * This test enforces semantic/pattern parity across the 5 copies of + * squad.agent.md (while `test/template-sync.test.ts` enforces byte-level parity) + * and the compatibility references so a future size-reduction refactor cannot + * silently relocate or contradict the always-on dispatch contract: * 1. An explicit INLINE-DISPATCH GATE in Client Compatibility — inline work is - * permitted ONLY in Direct Mode, or when NEITHER `task` NOR `runSubagent` - * is available; otherwise the coordinator MUST dispatch. + * permitted ONLY in Direct Mode; missing spawn tools require refusal. * 2. A one-line STOP gate under "How to Spawn an Agent" — about to produce a - * domain artifact with no spawn-tool call this turn → dispatch instead - * (unless Direct Mode / no spawn tool). + * domain artifact with no spawn-tool call this turn → dispatch instead. * 3. An always-on VS Code `runSubagent` micro-playbook so how-to-dispatch is * never lazy-loaded. + * 4. A mandatory first-turn Scribe bootstrap independent of domain dispatch. * * No subprocess is spawned here (kept deliberately read-only) so the test is * deterministic and immune to the parallel-suite `squad init` overwrite flake. @@ -52,6 +52,33 @@ const SQUAD_AGENT_LOCATIONS = [ 'packages/squad-cli/templates/squad.agent.md.template', 'packages/squad-sdk/templates/squad.agent.md.template', ] as const; +const ROUTING_LOCATIONS = [ + '.squad-templates/routing.md', + 'templates/routing.md', + 'packages/squad-cli/templates/routing.md', + 'packages/squad-sdk/templates/routing.md', +] as const; +const CLIENT_COMPATIBILITY_LOCATIONS = [ + '.squad-templates/client-compatibility-reference.md', + 'templates/client-compatibility-reference.md', + 'packages/squad-cli/templates/client-compatibility-reference.md', + 'packages/squad-sdk/templates/client-compatibility-reference.md', +] as const; +const SPAWN_REFERENCE_LOCATIONS = [ + '.squad-templates/spawn-reference.md', + 'templates/spawn-reference.md', + 'packages/squad-cli/templates/spawn-reference.md', + 'packages/squad-sdk/templates/spawn-reference.md', +] as const; +const CLIENT_COMPATIBILITY_SKILL_LOCATIONS = [ + '.copilot/skills/client-compatibility/SKILL.md', + '.squad-templates/skills/client-compatibility/SKILL.md', + 'templates/skills/client-compatibility/SKILL.md', + 'packages/squad-cli/templates/skills/client-compatibility/SKILL.md', + 'packages/squad-sdk/templates/skills/client-compatibility/SKILL.md', +] as const; +const CLIENT_COMPATIBILITY_DOC = + 'docs/src/content/docs/scenarios/client-compatibility.md'; /** * Stable anchor introduced by the fix. Phrasing of the surrounding sentence may @@ -66,12 +93,46 @@ function assertGateBody(content: string, label: string): void { const tail = content.slice(idx, idx + 600); // (a) inline is allowed in Direct Mode expect(tail, `${label}: gate must name Direct Mode as the inline exemption`).toMatch(/Direct Mode/); - // (b) inline is allowed only when NEITHER spawn tool exists — both tools named - expect(tail, `${label}: gate must reference the neither-task-nor-runSubagent fallback`).toMatch( - /neither[^.]*\btask\b[^.]*\brunSubagent\b|neither[^.]*\brunSubagent\b[^.]*\btask\b/i, - ); + // (b) all supported dispatch tools are named + expect(tail, `${label}: gate must reference create_session`).toMatch(/\bcreate_session\b/); + expect(tail, `${label}: gate must reference task`).toMatch(/\btask\b/); + expect(tail, `${label}: gate must reference runSubagent`).toMatch(/\brunSubagent\b/); // (c) otherwise dispatch is mandatory expect(tail, `${label}: gate must state dispatch is mandatory otherwise`).toMatch(/MUST dispatch/i); + expect(tail, `${label}: missing spawn tools must require refusal`).toMatch(/none is available, refuse/i); +} + +function assertMandatoryContract(content: string, label: string): void { + const idx = content.search(/Mandatory dispatch contract:/i); + expect(idx, `${label}: missing mandatory dispatch contract`).toBeGreaterThanOrEqual(0); + const tail = content.slice(idx, idx + 700); + expect(tail, `${label}: Direct Mode boundary must be narrow`).toMatch(/already present in context/i); + expect(tail, `${label}: domain work must be enumerated`).toMatch(/code, test, investigation, analysis/i); + expect(tail, `${label}: small tasks must still dispatch`).toMatch(/Small scope is not an exemption/i); +} + +function assertScribeBootstrap(content: string, label: string): void { + const idx = content.search(/Session Init — Scribe Bootstrap/i); + expect(idx, `${label}: missing first-turn Scribe bootstrap`).toBeGreaterThanOrEqual(0); + const tail = content.slice(idx, idx + 1000); + expect(tail, `${label}: bootstrap must run on the first Team Mode turn`).toMatch(/first Team Mode turn/i); + expect(tail, `${label}: bootstrap must not depend on prior agent work`).toMatch( + /must not depend on another agent having run/i, + ); + expect(tail, `${label}: CLI/App bootstrap must be background`).toMatch(/mode: "background"/i); + expect(tail, `${label}: VS Code bootstrap must use runSubagent`).toMatch(/\brunSubagent\b/i); +} + +function assertCompatibilityDispatchContract(content: string, label: string): void { + expect(content, `${label}: Copilot App must use create_session`).toMatch( + /Copilot App mode.{0,100}\bcreate_session\b/is, + ); + expect(content, `${label}: missing dispatch tools must require refusal`).toMatch( + /(?:No dispatch tool available|None available).{0,250}refuse domain work/is, + ); + expect(content, `${label}: stale inline fallback guidance remains`).not.toMatch( + /Fallback mode.{0,200}work inline/is, + ); } describe('coordinator inline-dispatch gate (regression #1035)', () => { @@ -97,14 +158,48 @@ describe('coordinator inline-dispatch gate (regression #1035)', () => { /runSubagent.{0,80}micro-playbook|micro-playbook.{0,80}runSubagent/is, ); }); + + it('has an exhaustive mandatory dispatch contract', () => { + assertMandatoryContract(content, CANONICAL); + expect(content, 'Lightweight Mode must still dispatch').toMatch( + /Lightweight Mode still dispatches one agent/i, + ); + }); + + it('starts Scribe on the first Team Mode turn', () => { + assertScribeBootstrap(content, CANONICAL); + }); + + describe('Scribe bootstrap routing parity', () => { + for (const loc of ROUTING_LOCATIONS) { + it(`${loc} starts Scribe at the beginning of Team Mode`, () => { + expect(read(loc)).toMatch(/Scribe always starts once at the beginning of every Team Mode session/i); + }); + } + }); + + describe('client compatibility reference parity', () => { + for (const loc of [ + ...CLIENT_COMPATIBILITY_LOCATIONS, + ...SPAWN_REFERENCE_LOCATIONS, + ...CLIENT_COMPATIBILITY_SKILL_LOCATIONS, + CLIENT_COMPATIBILITY_DOC, + ]) { + it(`${loc} preserves the mandatory dispatch contract`, () => { + assertCompatibilityDispatchContract(read(loc), loc); + }); + } + }); }); - describe('inline-dispatch gate parity across all 5 synced copies', () => { + describe('dispatch contract parity across all 5 synced copies', () => { for (const loc of SQUAD_AGENT_LOCATIONS) { - it(`${loc} contains the inline-dispatch gate`, () => { + it(`${loc} contains the mandatory dispatch and Scribe gates`, () => { const content = read(loc); expect(content, `${loc}: missing inline-dispatch gate anchor`).toMatch(GATE_ANCHOR); assertGateBody(content, loc); + assertMandatoryContract(content, loc); + assertScribeBootstrap(content, loc); }); } });