|
65 | 65 | index.ts CLI entry: verbs, dispatch, help |
66 | 66 | agent/ |
67 | 67 | director.ts ChatDirector; director-layer tool defs |
68 | | - prompts.ts System prompt builders; buildChatRole → Skywalker |
| 68 | + prompts.ts System prompt builders; buildChatRole → dispatch card |
69 | 69 | tools.ts Agent tool registration helpers |
70 | 70 | agent-search.ts search_agents tool + profile lexical index |
71 | 71 | default-agents.ts Built-in profiles = directorProfiles() spawn catalog |
@@ -159,18 +159,18 @@ Twenty packages under `src/agent/directors/<id>/` register in `DIRECTOR_REGISTRY |
159 | 159 |
|
160 | 160 | 1. `spawn_agent(agent=…)` / `spawn_agent(intent=…)` → `resolveDirector` in `agent-fleet.ts` before tools and system prompt are built. Bare `spawn_agent` (neither field) and `intent=general` fail closed. After director resolution, `createSpawnAgentTool` fail-closes implement/review (and their default directors) without non-empty `success_criteria`. |
161 | 161 | 2. `packageToProfile` maps envelope (`tools.allow`/`deny`) to `AgentProfile.capabilities` and `spawn.maySpawn` → `orchestrator`. System prompts are prefixed with a stable identity block (`formatDirectorSystemPrompt`: agent id, model role, optional skills). |
162 | | -3. Nested spawn: packages with `spawn.allowlist` forward that list into nested `spawn_agent` (`spawnAllowlist` on nestedDispatch). Off-list `agent` is refused. `spawn_agent(agent=skywalker)` is refused (primary is not a spawned worker). Primary omits the list so plugin profiles stay reachable. |
163 | | -4. `directorProfiles()` is the spawn catalog (`default-agents.ts`) — closed set minus skywalker. Plugin and local `.agents/agents/` profiles still load, but closed `DIRECTOR_IDS` cannot be overridden or aliased. |
164 | | -5. Primary chat role is Skywalker: `buildChatRole()` → `createSkywalkerSystemPrompt()`. The Skywalker card is a ~3–5k dispatcher (classify, tiny DIY, spawn named specialists); idle/mailbox/poll live in the harness, and family residuals come from `@corbits/prompt-variance`. Product mutation tools (`write_file` / `edit_file` / `delete_file`) live in CORE (and `SKYWALKER_TOOLS`) so they are advertised on the primary without a `tool_search` round-trip. DIY tiny/bounded edits on the parent; spawn builder/docs directors for substantial work — a prompt judgment call, not a toolset strip. `PRIMARY_DENIED_PRODUCT_TOOLS` is gone. Shell file-writes stay denied; MCP tools are not re-filtered by a product-write deny list. There is no static per-profile write-path lock (CL-6952). |
| 162 | +3. Nested spawn: packages with `spawn.allowlist` forward that list into nested `spawn_agent` (`spawnAllowlist` on nestedDispatch). Off-list `agent` is refused. `spawn_agent(agent=dispatch)` is refused (primary is not a spawned worker). Primary omits the list so plugin profiles stay reachable. |
| 163 | +4. `directorProfiles()` is the spawn catalog (`default-agents.ts`) — closed set minus dispatch. Plugin and local `.agents/agents/` profiles still load, but closed `DIRECTOR_IDS` cannot be overridden or aliased. |
| 164 | +5. Primary chat role is dispatch: `buildChatRole()` → `createDispatchSystemPrompt()`. The dispatch card is a ~3–5k dispatcher (classify, tiny DIY, spawn named specialists); idle/mailbox/poll live in the harness, and family residuals come from `@corbits/prompt-variance`. Product mutation tools (`write_file` / `edit_file` / `delete_file`) live in CORE (and `DISPATCH_TOOLS`) so they are advertised on the primary without a `tool_search` round-trip. DIY tiny/bounded edits on the parent; spawn coder/shakespeare directors for substantial work — a prompt judgment call, not a toolset strip. `PRIMARY_DENIED_PRODUCT_TOOLS` is gone. Shell file-writes stay denied; MCP tools are not re-filtered by a product-write deny list. There is no static per-profile write-path lock (CL-6952). |
165 | 165 |
|
166 | | - **Grok infer envelope.** `loadSessionChatPrompt` always appends `loadAgentContextExtensions` (`AGENTS.md`, capped at `MAX_AGENTS_MD_BYTES`) and advertises CORE+CATALOG full schemas via `advertisedToolNamesForSessionMode`. That assembly is family-agnostic — Grok does not substitute the trimmed director prompt (`buildSubAgentSystemPrompt` + `formatDirectorSystemPrompt`). Workers already use that trimmed path (no `AGENTS.md`, mounted-tool schemas only). Keep the infer envelope on Grok; do not strip `AGENTS.md` or core schemas. Measure in `src/agent/prompt-sizes.ts` (`assembleSkywalkerInferEnvelope` vs `assembleDirectorPrompt("skywalker", "grok")`). |
| 166 | + **Grok infer envelope.** `loadSessionChatPrompt` always appends `loadAgentContextExtensions` (`AGENTS.md`, capped at `MAX_AGENTS_MD_BYTES`) and advertises CORE+CATALOG full schemas via `advertisedToolNamesForSessionMode`. That assembly is family-agnostic — Grok does not substitute the trimmed director prompt (`buildSubAgentSystemPrompt` + `formatDirectorSystemPrompt`). Workers already use that trimmed path (no `AGENTS.md`, mounted-tool schemas only). Keep the infer envelope on Grok; do not strip `AGENTS.md` or core schemas. Measure in `src/agent/prompt-sizes.ts` (`assembleDirectorPrompt`). |
167 | 167 |
|
168 | 168 | **One advertised posix set (CL-8400).** Registry engines stay posix-named (`read_file`, `write_file`, `edit_file`, `delete_file`, `run_shell`, `search_files`, `grep`). Advertise is a 1:1 projection onto wire names (`read`, `write`, `edit`, `delete`, `bash`, `glob`, `grep`) plus the unchanged control-plane. Incoming aliases (wire names, old posix ids, Codex `shell` → `run_shell`, `update_plan` → `manage_tasks`) canonicalize onto the engine id for dispatch and grants. `apply_patch` is neither advertised nor dispatched (not an alias of `edit`). `list_dir` stays mounted and unadvertised. Director `tools.allow` stays engine names. Codex does not dual-publish `shell`+`run_shell`. Hidden `shell` coerces Codex `command` (string or `["bash","-lc",script]` argv), `workdir`, and `timeout_ms` onto `run_shell`. Hidden `update_plan` maps `plan: [{step, status}]` onto `manage_tasks(action: "create")` (`pending`/`in_progress`/`completed` → `todo`/`doing`/`done`). |
169 | 169 |
|
170 | 170 | 6. There is no static write-path declaration on packages or profiles (CL-6952 removed it — no shipped director ever set one). Instead, `agent-fleet.ts` tracks each running dispatch by cwd; a new mutating dispatch that lands on the same cwd as a live mutating peer (`pending_init`/`running`, and not a declared read-only `modelRole` of `explore`/`plan`/`review`/`test`) records at most one `concurrent-lane-overlap` entry per cwd wave in `intervention-log.ts` (class `conflict`). The wave flag clears when no live mutating writer remains for that cwd. Terminal-but-unsettled lanes (for example cancelled with `finishedAt` set while the run promise has not reached `finally`) are pruned from the map and do not warn. This is advisory only — it never blocks the spawn, since cwd overlap does not prove the two lanes touch the same files. |
171 | | -7. Spawn effort: pin > package `modelRole` default (`defaultEffortForDirector`; intern=low; plan/review/orchestrator=high; implement/explore/docs/test=medium) > orchestrator/worker binary > parent inheritance. Attached skills (style + philosophy on directors that listed both; never intern or Skywalker primary) are injected into the worker system prompt at spawn from plugin skill dirs only (no project-local `.agents`/`.claude`/`.codex` fallback). Optional skills are listed in the identity header for awareness; workers mount `skill_search` + `use_skill` on every family, scoped to the union of `attachedSkills` and `optionalSkills`. `use_skill` refuses names already attached or already loaded this session and does not return the body again. Primary mounts `use_skill` for its own skill list (same in-session refuse; no attached set). |
| 171 | +7. Spawn effort: pin > package `modelRole` default (`defaultEffortForDirector`; plan/review/orchestrator=high; implement/explore/docs/test=medium) > orchestrator/worker binary > parent inheritance. Attached skills (none on the shipped directors today; never the primary) are injected into the worker system prompt at spawn from plugin skill dirs only (no project-local `.agents`/`.claude`/`.codex` fallback). Optional skills are listed in the identity header for awareness; workers mount `skill_search` + `use_skill` on every family, scoped to the union of `attachedSkills` and `optionalSkills`. `use_skill` refuses names already attached or already loaded this session and does not return the body again. Primary mounts `use_skill` for its own skill list (same in-session refuse; no attached set). |
172 | 172 |
|
173 | | -Intent defaults: `intent=implement` → director `builder`; `explore` → `explorer`; `plan` → `counsel`; `review` → `critic`; general → error. Spawn: skywalker full fleet; all other directors, including greybeard, mount no fleet tools. Skywalker assigns one focused task per worker; fan-out width follows independent lanes (one lane per PR/path/ownership). Live `<env>` injects cwd, platform, arch, runtime, date, and git status on every chat and worker prompt. |
| 173 | +Intent defaults: `intent=implement` → director `coder`; `explore` → `explorer`; `plan` → `planner`; `review` → `reviewer`; general → error. Spawn: dispatch full fleet; all other directors mount no fleet tools. Dispatch assigns one focused task per worker; fan-out width follows independent lanes (one lane per PR/path/ownership). Live `<env>` injects cwd, platform, arch, runtime, date, and git status on every chat and worker prompt. |
174 | 174 |
|
175 | 175 | ### Auto Mode |
176 | 176 |
|
@@ -204,7 +204,7 @@ Listings are list-free, dumps are dump-locked: a bounded `ls`/`tree` prints name |
204 | 204 |
|
205 | 205 | `ChatInputProps` carries `isProcessing?: boolean` and `onInterrupt?: (message: string) => void`. When `isProcessing` is true, drain timing is **parent-idle** vs **session-idle**: |
206 | 206 |
|
207 | | -- **Enter** soft-steers while the parent is busy — enqueues kind `"steer"` and delivers at the next **parent** `tool.boundary` (the parent tool finishing, not a child). Does not interrupt. **Parent-idle** is when the primary Skywalker turn is not inside an in-flight parent tool; a long parent **foreground** `run_shell` is parent-busy and holds steers. A `run_shell` started with `background: true` returns at once and releases the boundary; its completion is delivered as a system message (`buildShellBackgroundMessage`, mailbox `system`, no operator-originated flag — it re-enters the reactor without counting as operator input) on a later turn. |
| 207 | +- **Enter** soft-steers while the parent is busy — enqueues kind `"steer"` and delivers at the next **parent** `tool.boundary` (the parent tool finishing, not a child). Does not interrupt. **Parent-idle** is when the primary dispatch turn is not inside an in-flight parent tool; a long parent **foreground** `run_shell` is parent-busy and holds steers. A `run_shell` started with `background: true` returns at once and releases the boundary; its completion is delivered as a system message (`buildShellBackgroundMessage`, mailbox `system`, no operator-originated flag — it re-enters the reactor without counting as operator input) on a later turn. |
208 | 208 |
|
209 | 209 | #### Background shell mode |
210 | 210 |
|
|
0 commit comments