From c280f6aa428dee92ee213f45d364557a5ea9a3a6 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Wed, 30 Sep 2026 13:40:56 -0700 Subject: [PATCH] docs: describe the ten-director fleet in ARCHITECTURE and PRODUCT --- docs/ARCHITECTURE.md | 92 +++++++++++++++++--------------------------- docs/PRODUCT.md | 16 ++++---- 2 files changed, 43 insertions(+), 65 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index ea1dd759c..01c95a997 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -152,7 +152,7 @@ Two directors, selected by role: Auto mode is toggled by CLI flags (`--auto` / `--no-auto`); there is currently no in-session key to toggle it (default on; constrained envelope — workspace writes and unconstrained shell auto-allow; installs, recursive rm, force/uncontained worktree changes, sensitive-path and opaque-wrapper shell still ask; contained non-force `git worktree add`/`remove`/`prune` and `list` auto-allow; shell file-mutation denied). It is not a separate edit/plan mode. -- **SubAgentDirector** (delegated work, `src/subagent/index.ts`) — Drives a dispatched worker until a turn arrives with no tool calls, then replies with the final assistant text and ends the run. A tool-less turn **after tools** completes only with the four-heading envelope (Summary, Findings, Blockers, Paths). Assistant text that prints explicit `` markup is treated as attempted tool use, not narration: one **verbatim-tool-call** nudge asks the worker to re-issue a real `tool_call` and does not count toward the tool-less spiral. A missing envelope otherwise nudges once (**incomplete-report**) and a second tool-less turn still without the envelope salvages as **incomplete-report-stop** (once; later tool-less turns wait). Explore/read-only workers that used tools then replied with findings remain normal completes; `requireEvidence` (off by default, set per director) additionally requires at least one read before a tool-less spawn-only reply can complete. `requirePlanSubstance` (counsel or `intent=plan`, not `modelRole === "plan"`) additionally requires Findings to contain files/paths, acceptance criteria, non-goals, risks, and ordered steps with a non-placeholder line each — four headings with stub Findings are incomplete-report, not an attachable plan. After real tool work, wrap-up Findings that are not placeholder or outline-only complete instead of being salvaged as a stub plan. Reads done through `run_shell` count as evidence too — `src/subagent/shell-evidence.ts` classifies shell reads (`cat`, `grep`, `sed` without `-i`, …) over the same subject expansion the auto-shell policy uses — but there is no corresponding shell-write evidence or file-write requirement: a run that never touches a file still completes normally once it replies with the envelope. There is no turn budget. Operator/parent cancel after any progress returns a **cancelled** salvage report (partial findings + tool activity) instead of a bare cancel string; cancel before progress still surfaces as cancelled-by-operator. There is no repetition/no-progress/never-acted/never-edited hard stop and no fingerprint-based re-dispatch block — a genuinely stuck worker runs until it completes, stalls, hits an opt-in wall-clock deadline, or is cancelled. +- **SubAgentDirector** (delegated work, `src/subagent/index.ts`) — Drives a dispatched worker until a turn arrives with no tool calls, then replies with the final assistant text and ends the run. A tool-less turn **after tools** completes only with the four-heading envelope (Summary, Findings, Blockers, Paths). Assistant text that prints explicit `` markup is treated as attempted tool use, not narration: one **verbatim-tool-call** nudge asks the worker to re-issue a real `tool_call` and does not count toward the tool-less spiral. A missing envelope otherwise nudges once (**incomplete-report**) and a second tool-less turn still without the envelope salvages as **incomplete-report-stop** (once; later tool-less turns wait). Explore/read-only workers that used tools then replied with findings remain normal completes; `requireEvidence` (off by default, set per director) additionally requires at least one read before a tool-less spawn-only reply can complete. `requirePlanSubstance` (planner or `intent=plan`, not `modelRole === "plan"`) additionally requires Findings to contain files/paths, acceptance criteria, non-goals, risks, and ordered steps with a non-placeholder line each — four headings with stub Findings are incomplete-report, not an attachable plan. After real tool work, wrap-up Findings that are not placeholder or outline-only complete instead of being salvaged as a stub plan. Reads done through `run_shell` count as evidence too — `src/subagent/shell-evidence.ts` classifies shell reads (`cat`, `grep`, `sed` without `-i`, …) over the same subject expansion the auto-shell policy uses — but there is no corresponding shell-write evidence or file-write requirement: a run that never touches a file still completes normally once it replies with the envelope. There is no turn budget. Operator/parent cancel after any progress returns a **cancelled** salvage report (partial findings + tool activity) instead of a bare cancel string; cancel before progress still surfaces as cancelled-by-operator. There is no repetition/no-progress/never-acted/never-edited hard stop and no fingerprint-based re-dispatch block — a genuinely stuck worker runs until it completes, stalls, hits an opt-in wall-clock deadline, or is cancelled. `spawn_agent` starts each worker and records it in the caller's fleet mailbox. On the TUI primary, mailbox mail is the collect path: occupancy takes uncollected terminals and re-enters the parent as system inbound with a Summary + Blockers digest (Findings when Summary is empty) and a blob pointer named for `read_file`. Nested orchestrators collect through mailbox mail the same way. A mounted `wait_agents` (exec primary) collects worker reports directly instead. Already-collected waits return status without a second report or error body. Wait JSON includes `stop_reason` from the session when present so a salvage that is wait-`done` is not mistaken for a clean complete, and so parent-initiated interrupt (`interrupted`) is not mistaken for operator-cancel (`cancelled`). Deadline salvage prepends an advisory parent hint suggesting continuation plus a longer deadline if more wall-clock time is warranted. Failed and incomplete-report salvage tell the parent to diagnose from the report or error and MAY spawn one successor with a changed brief. A parent-initiated interrupt is a resumable pause: wait unblocks with `stop_reason: interrupted` (often while the session is still running and has no report); the parent should `resume_agent` or re-wait, and must not spawn a successor against a still-live worker. Successor only if that session is no longer resumable. Operator-cancelled salvage asks the parent to synthesize Findings and Paths and wait for the operator instead of auto-starting another specialist. Identical re-dispatch of the same brief stays refused at the prompt / spawn-handoff layer, except a recoverable/continuable child failure (`continuable: true`) MAY spawn one successor with the same brief; there is no fingerprint-based re-dispatch hard-block. Deadline hints are advisory only — an identical re-dispatch is still admitted at runtime. Parent hints are prepended on salvage reports returned to the parent. The runtime does not auto-spawn successors. #### Model-family policy (`src/agent/model-family-policy.ts`) @@ -265,7 +265,7 @@ Every director package carries a required `tier: SubagentTier` field (`src/agent | Tier | Who | Fleet surface | | ------------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -| 1 — `orchestrator` | skywalker (primary) | Full fleet control over the whole tree. | +| 1 — `orchestrator` | dispatch (primary) | Full fleet control over the whole tree. | | 2 — `nested-orchestrator` | any package with `spawn.maySpawn` (no closed director uses this tier today) | Same fleet surface, scoped to its own subtree: may manage only its own descendants, never a sibling or ancestor. | | 3 — worker | every other director (`tier: "leaf"` on the package) | No fleet verbs. Mounts `ask_director` and `submit_result`. | @@ -282,66 +282,46 @@ Every shipped specialist is a **director package** — a prompt-first `DirectorP **Primary** -| Director | Owns | Does not own | -| --------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | -| skywalker | Dispatcher — classify, DIY tiny edits, spawn named specialists, synthesize | Substantial product work without spawning; being the implementer/reviewer by default | - -**Engineering directors** - -| Director | Owns | Does not own | -| ----------- | ----------------------------------------------------------------------- | ---------------------------------- | -| builder | Ship product code | Pure docs, pure review | -| explorer | Map/read codebase | Product edits | -| counsel | Eng change plan (steps, paths, tests, risks) | Arch gate, product discovery, code | -| intern | Mechanical commands only | Ambiguous or product-design work | -| critic | Evidence-based code review | Fixing product code | -| greybeard | Architecture/approach review of plans/docs | Authoring eng plans, implementing | -| neckbeard | Adversarial hygiene / refactor stress | Real review substitute | -| bruckheimer | Product discovery → PRODUCT/ARCHITECTURE/IMPLEMENTATION-oriented briefs | Eng plan, code | -| gaasbot | Quick CTO opinion voice | Formal review gate, implement | -| migrator | Reversible settings/config/session-state migrations | Live-state execution, new features | -| warden | Trust review of permission/provider-auth/plugin-loader diffs | Fixes, general review | - -**Design trio (dev perspective)** - -| Director | Owns | -| -------- | ----------------------------------------------------- | -| draper | Product visual / design-system critique | -| emil | Design-engineering + software laws on product UI/code | -| rand | **DESIGN.md** create-if-missing + alignment gate | - -**Docs + QA** - -| Director | Owns | -| ----------- | ------------------------------------------------------------------------------------- | -| shakespeare | Docs maintain (docs core baked into prompt); PRODUCT/ARCHITECTURE/IMPLEMENTATION lane | -| testsmith | Test design only (what/how to test) | -| tester | Runtime verification; never fix product code | -| gauntlet | Mutation/vacuity check that named tests can actually fail | -| prober | Measure-only latency/behavior probe per family/model | +| Director | Owns | Does not own | +| -------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | +| dispatch | Dispatcher — classify, DIY tiny edits, spawn named specialists, synthesize | Substantial product work without spawning; being the implementer/reviewer by default | + +**Specialists** + +| Director | Owns | Does not own | +| ----------- | -------------------------------------------------------------------- | ---------------------- | +| explorer | Read-only codebase mapping | Product edits | +| planner | PRD.md, SOLUTION_SCOPE.md, BUILD_PLAN.md authoring | Code | +| coder | Minimal safe diffs, root-cause fixes, tests | Pure docs, pure review | +| reviewer | Evidence-based defect and quality review with temp-test verification | Fixing product code | +| designer | DESIGN.md, design laws, tokens, interface polish | Non-UI product code | +| artist | SVGs, diagrams, generative graphic prompts | Product code | +| warden | Trust review of permission, provider-auth, and plugin-loader diffs | Fixes, general review | +| shakespeare | Docs maintenance (PRODUCT / ARCHITECTURE / IMPLEMENTATION) | Product code | +| prober | Measure-only latency and behavior probe per family/model | Fixes, product edits | **Intent → director** (`spawn_agent(intent=…)` when `agent` is omitted). implement/review (and their default directors) fail closed without non-empty `success_criteria`. -| Intent | Default director | -| --------- | -------------------------------- | -| implement | builder | -| explore | explorer | -| plan | counsel | -| review | critic (override with `agent=…`) | -| general | **none** — reclassify only | +| Intent | Default director | +| --------- | ---------------------------------- | +| implement | coder | +| explore | explorer | +| plan | planner | +| review | reviewer (override with `agent=…`) | +| general | **none** — reclassify only | **Spawn matrix** -| Who | Spawn rights | -| --------------------------- | ------------------------- | -| skywalker (primary session) | Full closed fleet | -| All other directors | no fleet delegation tools | +| Who | Spawn rights | +| -------------------------- | ------------------------- | +| dispatch (primary session) | Full closed fleet | +| All other directors | no fleet delegation tools | -**Tool envelopes** prefer small `tools.allow` mounts over deny-everything. Shipped docs/design directors (shakespeare, rand, bruckheimer) mount write tools with no path-level lock. Lane routing is spawn policy (shakespeare = P/A/I docs, rand = DESIGN.md, bruckheimer = product discovery), not a file lock. There is no static per-package write-path declaration (CL-6952 removed it — no shipped director ever set one); instead spawn_agent records, without blocking, when two concurrently running dispatches land on the same cwd (see `intervention-log.ts`'s `conflict` class). +**Tool envelopes** prefer small `tools.allow` mounts over deny-everything. Shipped docs/design directors (shakespeare, designer, planner) mount write tools with no path-level lock. Lane routing is spawn policy (shakespeare = P/A/I docs, designer = DESIGN.md, planner = PRD/scope/build plan), not a file lock. There is no static per-package write-path declaration (CL-6952 removed it — no shipped director ever set one); instead spawn_agent records, without blocking, when two concurrently running dispatches land on the same cwd (see `intervention-log.ts`'s `conflict` class). -**Typical chain:** bruckheimer → counsel → greybeard → builder (+ intern) → critic (+ optional neckbeard), with skywalker coordinating throughout. +**Typical chain:** planner → coder → reviewer (explorer up front when the code is unfamiliar), with dispatch coordinating throughout. -**Reasoning effort by role** (`src/provider/reasoning-effort.ts` → `resolveEffortForRole` / `defaultEffortForDirector`): package `modelRole` defaults are orchestrator/plan/review → `high`, implement/explore/docs/test → `medium`, with **intern** pinned to `low`. Spawn-time binary fallback is orchestrator → `high`, worker → `medium`, clamped to the model. Explicit profile inference pins win; parent session effort is only a fallback when the role default is unsupported. This keeps multi-agent fleets off the sol+high latency cliff. +**Reasoning effort by role** (`src/provider/reasoning-effort.ts` → `resolveEffortForRole` / `defaultEffortForDirector`): package `modelRole` defaults are orchestrator/plan/review → `high`, implement/explore/docs/test → `medium`. Spawn-time binary fallback is orchestrator → `high`, worker → `medium`, clamped to the model. Explicit profile inference pins win; parent session effort is only a fallback when the role default is unsupported. This keeps multi-agent fleets off the sol+high latency cliff. **Session records** (`src/subagent/session-store.ts`): each spawn is retained as an inspectable child session (id, profile, description, brief, status, tool activity, transcript entries). Child events land only in this store — not in the parent chat transcript. Live progress still uses the light `onProgress` channel for the status bar. Completed sessions are capped (`maxCompleted`) so a long chat does not grow without bound. @@ -353,16 +333,16 @@ Data-only agent plugins (`src/plugins/data-only-agent.ts`) synthesize `agentPlug ### System Prompt (`src/agent/prompts.ts`) -The primary session identity is **Skywalker** (`buildChatRole` → `createSkywalkerSystemPrompt`). Product name remains Corbits Code; when asked its name, the primary answers Skywalker. Role: dispatcher — classify, DIY tiny/single-file/one-route product edits (Builder neighborhood), spawn named closed directors via `spawn_agent` for substantial work, track the fleet, synthesize. The Skywalker card is a ~3–5k operator-surface prompt; idle, mailbox delivery, and poll-avoidance live in the harness (tool descriptions and occupancy), not the card. Family residuals append via `@corbits/prompt-variance` at assembly (model-family policy) — do not inline family text in the card. Product mutation tools (`write_file` / `edit_file` / `delete_file`) are mounted on the primary session (CORE and `SKYWALKER_TOOLS`) so Skywalker can DIY bounded edits; spawn remains the default for substantial, multi-file, parallel, or specialist work. Shell file-writes stay denied by auto-shell policy. MCP tools are not re-filtered by a product-write deny list (that list is gone). There is no static per-worker write-path lock; concurrent lanes sharing a cwd are instead flagged (not blocked) as a `conflict` intervention. A frontier model already knows how to code; the static prompt carries harness-specific facts and the closed-fleet routing policy. The base is three individually-exported sections: +The primary session identity is **Skywalker** (`buildChatRole` → `createSkywalkerSystemPrompt`). Product name remains Corbits Code; when asked its name, the primary answers Skywalker. Role: dispatcher — classify, DIY tiny/single-file/one-route product edits , spawn named closed directors via `spawn_agent` for substantial work, track the fleet, synthesize. The Skywalker card is a ~3–5k operator-surface prompt; idle, mailbox delivery, and poll-avoidance live in the harness (tool descriptions and occupancy), not the card. Family residuals append via `@corbits/prompt-variance` at assembly (model-family policy) — do not inline family text in the card. Product mutation tools (`write_file` / `edit_file` / `delete_file`) are mounted on the primary session (CORE and `SKYWALKER_TOOLS`) so Skywalker can DIY bounded edits; spawn remains the default for substantial, multi-file, parallel, or specialist work. Shell file-writes stay denied by auto-shell policy. MCP tools are not re-filtered by a product-write deny list (that list is gone). There is no static per-worker write-path lock; concurrent lanes sharing a cwd are instead flagged (not blocked) as a `conflict` intervention. A frontier model already knows how to code; the static prompt carries harness-specific facts and the closed-fleet routing policy. The base is three individually-exported sections: - `buildChatRole` — Skywalker dispatcher card (operator surface; classify; DIY tiny/bounded product edits; spawn named specialists). -- `buildHarnessFacts` — the non-derivable rules: shell file-writes are blocked, path tools are the DIY surface on primary (spawn builder/docs directors for substantial work), dependency installs and off-limits paths need approval, images are native multimodal input, core tools plus the advertised catalog (including `skill_search`) are resident (MCP and other unadvertised tools load via `tool_search`; use `search_agents` before dispatching specialists), workflows run only from slash-command steps, and session memory lives at `.corbits/MEMORY.md`. +- `buildHarnessFacts` — the non-derivable rules: shell file-writes are blocked, path tools are the DIY surface on primary (spawn coder/shakespeare directors for substantial work), dependency installs and off-limits paths need approval, images are native multimodal input, core tools plus the advertised catalog (including `skill_search`) are resident (MCP and other unadvertised tools load via `tool_search`; use `search_agents` before dispatching specialists), workflows run only from slash-command steps, and session memory lives at `.corbits/MEMORY.md`. - `buildGuidelines` — be concise, prefer `spawn_agent` (mailbox mail on TUI; exec-primary `wait_agents`) for substantial product work with one focused task per worker and fan-out by independent lanes, DIY tiny/bounded edits on the parent, answer questions and diagnose visual/product feedback before editing, work autonomously for explicit coding tasks, use `lsp` for symbol work, and require implementation agents to run the repository-defined typecheck, relevant tests, and every defined full verification command. Agents report exact commands, outcomes, and exit statuses; a repository with no typecheck command produces an explicit Blocker backed by project-configuration evidence rather than an invented command or silent skip. - `buildPromptDisciplineBlock` — a shared, prohibition-form section appended exactly once to every built prompt (chat and sub-agent, every provider family). Primary vs worker wording differs for product writes: workers are told to use `read_file`/`edit_file`/`write_file`; Skywalker is told to DIY tiny/bounded edits with those path tools and spawn directors for substantial work. Shared rules: never `cat`/`sed`/heredoc/`echo` for file work, no setting or exporting environment variables (recurring needs belong in project settings), `web_fetch`/`web_search` instead of `curl`/`wget`/hand-rolled queries, one operation per `run_shell` call, turn semantics (a tool-less reply is the final answer, no repeat searches, stop and change approach after three failed attempts, batch independent reads in parallel), and TTY output rules (short bold headers, one-line bullets, backticks for paths/commands, no wide tables). **Provider-conditional residuals.** Per-family additions layer on top of the shared block via the same `ModelFamilyPolicy` mechanism the directors use (`src/subagent/provider-family.ts`, `src/agent/model-family-policy.ts`) — additive lines, never prompt forks. **Grok** leaves get `buildGrokLeafAntiThrashNote` (gated by `shouldApplyGrokAntiThrash` / `applyGrokFinishBias`, withheld from orchestrators): a compact finish-bias reinforcement plus a one-line reminder to route file/web work through the dedicated tools rather than `run_shell`, motivated by observed tool-routing thrash on the same harness. **Kimi** intentionally has no residual yet — `detectModelFamily` already resolves the family so callers can branch on it, but the prompt seam is left unfilled pending eval characterization of Kimi's behavior, mirroring the provisional (permissive-default) policy in `model-family-policy.ts`. -`buildChatSystemPrompt` (TUI chat) assembles: base → core tool list → name-only skills listing → live `` block → appended extensions. `buildSubAgentSystemPrompt` assembles the worker prompt without a catalog skills listing. Closed directors that declare `attachedSkills` (style + philosophy on those that listed both; never intern or Skywalker primary) get those bodies injected once at spawn from **plugin skill dirs only** (`skillDirsFromEnabledPlugins`) — `resolveSkillBody` is called with `pluginDirsOnly`, so a project-local `.agents`/`.claude`/`.codex/skills` SKILL.md cannot become system-prompt constraints. A miss is noted in the attached section; the worker proceeds (no park). Optional skills stay names-only in the identity header; workers mount `skill_search` + `use_skill` on every family (including grok/kimi leaves), scoped to the union of `attachedSkills` and `optionalSkills`. Built-in catalog tools (including `skill_search`) are advertised on the primary wire and callable directly; MCP integrations are discovered via `tool_search` rather than being enumerated. Skills follow the same lazy principle on the primary: each discovered skill contributes only its name. The model calls `skill_search` for descriptions when choosing, then `use_skill` to load a body. The operator can also invoke the same skill as `/` (see Skills below). Skills are discovered (and deduped by name, first-wins) from enabled plugin dirs, then `.agents`/`.claude`/`.codex/skills`, in that precedence. Corbits Code ships a bundled catalog via the first-party `corbits-skills` plugin (origin `repo`); project-local skills of the same name are shadowed by an enabled plugin skill. +`buildChatSystemPrompt` (TUI chat) assembles: base → core tool list → name-only skills listing → live `` block → appended extensions. `buildSubAgentSystemPrompt` assembles the worker prompt without a catalog skills listing. Closed directors that declare `attachedSkills` (none of the shipped directors do today; never the primary) get those bodies injected once at spawn from **plugin skill dirs only** (`skillDirsFromEnabledPlugins`) — `resolveSkillBody` is called with `pluginDirsOnly`, so a project-local `.agents`/`.claude`/`.codex/skills` SKILL.md cannot become system-prompt constraints. A miss is noted in the attached section; the worker proceeds (no park). Optional skills stay names-only in the identity header; workers mount `skill_search` + `use_skill` on every family (including grok/kimi leaves), scoped to the union of `attachedSkills` and `optionalSkills`. Built-in catalog tools (including `skill_search`) are advertised on the primary wire and callable directly; MCP integrations are discovered via `tool_search` rather than being enumerated. Skills follow the same lazy principle on the primary: each discovered skill contributes only its name. The model calls `skill_search` for descriptions when choosing, then `use_skill` to load a body. The operator can also invoke the same skill as `/` (see Skills below). Skills are discovered (and deduped by name, first-wins) from enabled plugin dirs, then `.agents`/`.claude`/`.codex/skills`, in that precedence. Corbits Code ships a bundled catalog via the first-party `corbits-skills` plugin (origin `repo`); project-local skills of the same name are shadowed by an enabled plugin skill. **Overrides.** `loadSystemPromptOverrides` (`src/agent/context-extensions.ts`) resolves a project `SYSTEM.md` (repo root, then `.corbits/`) that **replaces** the static base block, and an `APPEND_SYSTEM.md` that is **appended** as an extension. These compose with `config.systemPromptExtensions` (profile config) and the auto-discovered `AGENTS.md`, all of which attach as appended sections after the base. diff --git a/docs/PRODUCT.md b/docs/PRODUCT.md index da11483e0..6e12b7162 100644 --- a/docs/PRODUCT.md +++ b/docs/PRODUCT.md @@ -155,16 +155,14 @@ Capabilities beyond the core toolset are opt-in plugins, enabled per workspace t ## Multi-agent (fleet agents) -The primary session is always **orchestrator** (single-agent mode is gone). Its identity is **Skywalker** (product name remains Corbits Code; when asked its name, answer Skywalker): classify work, DIY tiny/single-file/one-route product edits, dispatch a **closed fleet of 20 directors** for substantial work, track the fleet, and synthesize. Product mutation tools (`write_file` / `edit_file` / `delete_file`) are mounted on the primary (CORE / `SKYWALKER_TOOLS`) — path tools are the DIY surface; spawn remains the default for substantial, multi-file, parallel, or specialist work. Shell file-writes stay denied. MCP tools are not re-filtered by a product-write deny list (that list is gone). There is no static per-package write-path declaration (CL-6952 removed it — no shipped director ever set one). A concurrent dispatch landing on the same working directory as another still-running lane is recorded as a `conflict` intervention, not blocked. Operator slash recipes (`/implement`, `/plan`, `/refactor`, `/review`, `/pull-request`, `/issue`, `/docs`, `/interview`) tell Skywalker which directors to spawn for substantial work (`/lexicon` runs on the primary and spawns nothing); tiny/bounded edits may run on the primary. +The primary session is always **orchestrator** (single-agent mode is gone). Its identity is **Skywalker** (product name remains Corbits Code; when asked its name, answer Skywalker): classify work, DIY tiny/single-file/one-route product edits, dispatch a **closed fleet of 10 directors** for substantial work, track the fleet, and synthesize. Product mutation tools (`write_file` / `edit_file` / `delete_file`) are mounted on the primary (CORE / `SKYWALKER_TOOLS`) — path tools are the DIY surface; spawn remains the default for substantial, multi-file, parallel, or specialist work. Shell file-writes stay denied. MCP tools are not re-filtered by a product-write deny list (that list is gone). There is no static per-package write-path declaration (CL-6952 removed it — no shipped director ever set one). A concurrent dispatch landing on the same working directory as another still-running lane is recorded as a `conflict` intervention, not blocked. Operator slash recipes (`/implement`, `/plan`, `/refactor`, `/review`, `/pull-request`, `/issue`, `/docs`, `/interview`) tell Skywalker which directors to spawn for substantial work; tiny/bounded edits may run on the primary. -| Lane | Directors | -| --------- | -------------------------------------------------------------------------------------------------------- | -| Primary | skywalker | -| Eng | builder, explorer, counsel, intern, critic, greybeard, neckbeard, bruckheimer, gaasbot, migrator, warden | -| Design | draper, emil, rand | -| Docs / QA | shakespeare, testsmith, tester, gauntlet, prober | +| Role | Directors | +| ---------- | --------------------------------------------------------------------------------- | +| Primary | dispatch | +| Specialist | explorer, planner, coder, reviewer, designer, artist, warden, shakespeare, prober | -There is **no catch-all worker**. `spawn_agent` requires `agent=…` or a non-general `intent` (implement/explore/plan/review→critic); bare dispatch and `intent=general` are refused. Named `spawn_agent(agent=…)` selects a director package without requiring a plugin profile, except `skywalker` which is the primary session identity and is refused as a spawned worker. Nested spawn is runtime-enforced: only skywalker (full fleet allowlist) may spawn; all other workers, including greybeard, have no fleet tools. Primary omits an allowlist so plugin profiles remain reachable from the main session. +There is **no catch-all worker**. `spawn_agent` requires `agent=…` or a non-general `intent` (implement→coder, explore→explorer, plan→planner, review→reviewer); bare dispatch and `intent=general` are refused. Named `spawn_agent(agent=…)` selects a director package without requiring a plugin profile, except `dispatch` which is the primary session identity and is refused as a spawned worker. Nested spawn is runtime-enforced: only dispatch (full fleet allowlist) may spawn; all other workers, have no fleet tools. Primary omits an allowlist so plugin profiles remain reachable from the main session. Corbits Code fans work out to short-lived **fleet agents** — workers with their own loop, tools, and checklist — while the primary session stays focused. Each worker gets one focused task; fan-out width follows independent lanes (one lane per PR/path/ownership). @@ -172,7 +170,7 @@ Corbits Code fans work out to short-lived **fleet agents** — workers with thei - **Tasks** are checklist items owned by one agent via `manage_tasks`. - **Fleet agents** are spawned with `spawn_agent`. On the TUI primary, mailbox mail arrives as inbound when a worker finishes or fails — spawn then idle; do not poll. Nested orchestrators collect through mailbox mail the same way. Workers ask the parent with `ask_director`. That parks a question while the worker stays `running`. On an exec-primary run, `wait_agents` returns `awaiting_director` with a question payload — that is not terminal. Once a parked ask is surfaced, `list_agents` fails closed until `send_input` answers or the ask is dropped — do not poll `list_agents`. The parent answers with `send_input` (`target` = the worker's session id). On the TUI primary, a parked question arrives as a synthetic idle-send wake. Escalate to the human only with `ask_operator`. -Dispatch uses a structured brief (context / goal / optional goals seed) and returns a structured report. The TUI Agents strip and fleet board show who is running; live tool progress updates the status bar without dumping the child transcript into the parent chat. There is no turn budget. A tool-less final turn completes only with the four-heading report envelope. Printed `` markup in assistant text gets one corrective nudge to issue a real tool call and does not count as the wrap-up; without the envelope, one incomplete-report nudge is given and a second tool-less turn without the envelope salvages as `incomplete-report-stop` (once; later tool-less turns wait). Counsel and `intent=plan` also require plan substance in Findings (files/paths, acceptance criteria, non-goals, risks, ordered steps); headings-only or stub Findings salvage as `incomplete-report`, not an attachable plan. After real tool work, wrap-up Findings that are not placeholder or outline-only complete. A silent worker (no activity for `stallTimeoutMs`, opt-in) gets one continuation nudge, then salvages as `stalled` only after a full `stallTimeoutMs` grace with still no activity — queued checks inside that window wait, they do not salvage. An opt-in `deadlineMs`, or an operator cancel, can also end a run early. Each of these returns a salvage report so a runaway or idle child cannot quietly burn a large token budget or look done after prose alone. +Dispatch uses a structured brief (context / goal / optional goals seed) and returns a structured report. The TUI Agents strip and fleet board show who is running; live tool progress updates the status bar without dumping the child transcript into the parent chat. There is no turn budget. A tool-less final turn completes only with the four-heading report envelope. Printed `` markup in assistant text gets one corrective nudge to issue a real tool call and does not count as the wrap-up; without the envelope, one incomplete-report nudge is given and a second tool-less turn without the envelope salvages as `incomplete-report-stop` (once; later tool-less turns wait). The planner and `intent=plan` also require plan substance in Findings (files/paths, acceptance criteria, non-goals, risks, ordered steps); headings-only or stub Findings salvage as `incomplete-report`, not an attachable plan. After real tool work, wrap-up Findings that are not placeholder or outline-only complete. A silent worker (no activity for `stallTimeoutMs`, opt-in) gets one continuation nudge, then salvages as `stalled` only after a full `stallTimeoutMs` grace with still no activity — queued checks inside that window wait, they do not salvage. An opt-in `deadlineMs`, or an operator cancel, can also end a run early. Each of these returns a salvage report so a runaway or idle child cannot quietly burn a large token budget or look done after prose alone. ## Business Justification