From 65ab14bb9fe607a4206bb6d2f1be16b98df280e6 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sat, 22 Aug 2026 00:39:46 -0700 Subject: [PATCH 1/6] Rename the implement director id to build --- scripts/eval-capability.test.ts | 6 ++-- src/agent/directors/build/index.ts | 1 + .../{implement => build}/package.test.ts | 30 +++++++++---------- .../directors/{implement => build}/package.ts | 8 ++--- src/agent/directors/identity.test.ts | 10 +++---- src/agent/directors/implement/index.ts | 1 - src/agent/directors/registry.test.ts | 6 ++-- src/agent/directors/registry.ts | 6 ++-- src/agent/directors/skywalker/package.test.ts | 2 +- src/agent/directors/skywalker/package.ts | 6 ++-- src/agent/directors/tool-sets.test.ts | 4 +-- src/agent/directors/tool-sets.ts | 4 +-- src/agent/directors/types.ts | 2 +- src/config.test.ts | 14 +++++++-- tests/unit/exec/runner.test.ts | 8 ++--- 15 files changed, 58 insertions(+), 50 deletions(-) create mode 100644 src/agent/directors/build/index.ts rename src/agent/directors/{implement => build}/package.test.ts (65%) rename src/agent/directors/{implement => build}/package.ts (93%) delete mode 100644 src/agent/directors/implement/index.ts diff --git a/scripts/eval-capability.test.ts b/scripts/eval-capability.test.ts index 47555c88c..1f8460a54 100644 --- a/scripts/eval-capability.test.ts +++ b/scripts/eval-capability.test.ts @@ -119,9 +119,9 @@ describe("parseArgs", () => { ); }); - test("--director implement is parsed", () => { - const opts = parseArgs(["--provider", "foo", "--model", "bar", "--director", "implement"]); - expect(opts.director).toBe("implement"); + test("--director build is parsed", () => { + const opts = parseArgs(["--provider", "foo", "--model", "bar", "--director", "build"]); + expect(opts.director).toBe("build"); }); test("omitted --director stays undefined", () => { diff --git a/src/agent/directors/build/index.ts b/src/agent/directors/build/index.ts new file mode 100644 index 000000000..5d474bbd7 --- /dev/null +++ b/src/agent/directors/build/index.ts @@ -0,0 +1 @@ +export { buildDirectorPackage } from "./package.js"; diff --git a/src/agent/directors/implement/package.test.ts b/src/agent/directors/build/package.test.ts similarity index 65% rename from src/agent/directors/implement/package.test.ts rename to src/agent/directors/build/package.test.ts index 7519777a2..f941fd4ba 100644 --- a/src/agent/directors/implement/package.test.ts +++ b/src/agent/directors/build/package.test.ts @@ -1,33 +1,33 @@ import { describe, expect, test } from "bun:test"; -import { implementPackage } from "./package.js"; +import { buildDirectorPackage } from "./package.js"; -describe("implementPackage", () => { +describe("buildDirectorPackage", () => { test("id matches directory / registry id", () => { - expect(implementPackage.id).toBe("implement"); + expect(buildDirectorPackage.id).toBe("build"); }); test("systemPrompt is non-empty and not a Placeholder", () => { - expect(implementPackage.systemPrompt.length).toBeGreaterThan(0); - expect(implementPackage.systemPrompt.startsWith("Placeholder")).toBe(false); + expect(buildDirectorPackage.systemPrompt.length).toBeGreaterThan(0); + expect(buildDirectorPackage.systemPrompt.startsWith("Placeholder")).toBe(false); }); test("systemPrompt mentions PRIMARY INTENT", () => { - expect(implementPackage.systemPrompt).toContain("PRIMARY INTENT"); + expect(buildDirectorPackage.systemPrompt).toContain("PRIMARY INTENT"); }); test("spawn.maySpawn is false (leaf)", () => { - expect(implementPackage.spawn.maySpawn).toBe(false); + expect(buildDirectorPackage.spawn.maySpawn).toBe(false); }); test("tools.allow includes product write tools", () => { - const allow = implementPackage.tools?.allow ?? []; + const allow = buildDirectorPackage.tools?.allow ?? []; expect(allow).toContain("write_file"); expect(allow).toContain("edit_file"); expect(allow).toContain("delete_file"); }); test("report.requiredSections includes Summary, Findings, Blockers, Paths", () => { - const sections = implementPackage.report.requiredSections; + const sections = buildDirectorPackage.report.requiredSections; expect(sections).toContain("Summary"); expect(sections).toContain("Findings"); expect(sections).toContain("Blockers"); @@ -35,36 +35,36 @@ describe("implementPackage", () => { }); test("modelRole is implement", () => { - expect(implementPackage.modelRole).toBe("implement"); + expect(buildDirectorPackage.modelRole).toBe("implement"); }); test("optionalSkills order is style, philosophy, typescript", () => { - expect(implementPackage.optionalSkills).toEqual(["style", "philosophy", "typescript"]); + expect(buildDirectorPackage.optionalSkills).toEqual(["style", "philosophy", "typescript"]); }); test("systemPrompt has DONE GATE for success_criteria", () => { - const prompt = implementPackage.systemPrompt; + const prompt = buildDirectorPackage.systemPrompt; expect(prompt).toContain("DONE GATE"); expect(prompt).toContain("success_criteria"); expect(prompt).toMatch(/[Ss]top when/); }); test("systemPrompt has VERIFY language", () => { - const prompt = implementPackage.systemPrompt; + const prompt = buildDirectorPackage.systemPrompt; expect(prompt).toContain("VERIFY"); expect(prompt).toMatch(/typecheck|tests/); expect(prompt).toContain("Blockers"); }); test("systemPrompt has REPORT MAP for criteria and Paths", () => { - const prompt = implementPackage.systemPrompt; + const prompt = buildDirectorPackage.systemPrompt; expect(prompt).toContain("REPORT MAP"); expect(prompt).toMatch(/success_criteria.*pass|fail|blocked/s); expect(prompt).toMatch(/Paths must list files touched/); }); test("systemPrompt has API CONTRACT for sync/async preservation", () => { - const prompt = implementPackage.systemPrompt; + const prompt = buildDirectorPackage.systemPrompt; expect(prompt).toContain("API CONTRACT"); expect(prompt).toMatch(/sync/i); expect(prompt).toMatch(/Promise|async/); diff --git a/src/agent/directors/implement/package.ts b/src/agent/directors/build/package.ts similarity index 93% rename from src/agent/directors/implement/package.ts rename to src/agent/directors/build/package.ts index 1637d4c06..6340760be 100644 --- a/src/agent/directors/implement/package.ts +++ b/src/agent/directors/build/package.ts @@ -1,8 +1,8 @@ import type { DirectorPackage } from "../types.js"; -import { IMPLEMENT_TOOLS } from "../tool-sets.js"; +import { BUILD_TOOLS } from "../tool-sets.js"; -export const implementPackage: DirectorPackage = { - id: "implement", +export const buildDirectorPackage: DirectorPackage = { + id: "build", primaryIntent: "Ship product code with tests to satisfy the brief", outOfLane: [ "architecture gates", @@ -13,7 +13,7 @@ export const implementPackage: DirectorPackage = { ], description: "Implementation leaf — edit, verify, report", optionalSkills: ["style", "philosophy", "typescript"], - tools: { allow: IMPLEMENT_TOOLS }, + tools: { allow: BUILD_TOOLS }, spawn: { maySpawn: false }, nudge: { maxTurns: 60 }, report: { requiredSections: ["Summary", "Findings", "Blockers", "Paths"] }, diff --git a/src/agent/directors/identity.test.ts b/src/agent/directors/identity.test.ts index b48ac8057..1052f3745 100644 --- a/src/agent/directors/identity.test.ts +++ b/src/agent/directors/identity.test.ts @@ -8,12 +8,12 @@ import { DIRECTOR_REGISTRY } from "./registry.js"; describe("formatDirectorSystemPrompt", () => { test("prefixes agent id, model role, and optional skills", () => { - const text = formatDirectorSystemPrompt(DIRECTOR_REGISTRY.implement); - expect(text.startsWith("Identity: agent id `implement`")).toBe(true); - expect(text).toContain('task(agent="implement")'); + const text = formatDirectorSystemPrompt(DIRECTOR_REGISTRY.build); + expect(text.startsWith("Identity: agent id `build`")).toBe(true); + expect(text).toContain('task(agent="build")'); expect(text).toContain("Model role: implement."); expect(text).toContain("style, philosophy, typescript"); - expect(text).toContain(DIRECTOR_REGISTRY.implement.systemPrompt); + expect(text).toContain(DIRECTOR_REGISTRY.build.systemPrompt); }); test("intern reports no optional skills by default", () => { @@ -25,7 +25,7 @@ describe("formatDirectorSystemPrompt", () => { describe("defaultEffortForDirector", () => { test("intern is low; implement is medium; greybeard is high", () => { expect(defaultEffortForDirector(DIRECTOR_REGISTRY.intern)).toBe("low"); - expect(defaultEffortForDirector(DIRECTOR_REGISTRY.implement)).toBe( + expect(defaultEffortForDirector(DIRECTOR_REGISTRY.build)).toBe( MODEL_ROLE_DEFAULT_EFFORT.implement, ); expect(defaultEffortForDirector(DIRECTOR_REGISTRY.greybeard)).toBe("high"); diff --git a/src/agent/directors/implement/index.ts b/src/agent/directors/implement/index.ts deleted file mode 100644 index ad613f288..000000000 --- a/src/agent/directors/implement/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { implementPackage } from "./package.js"; diff --git a/src/agent/directors/registry.test.ts b/src/agent/directors/registry.test.ts index 47797cdb9..826853434 100644 --- a/src/agent/directors/registry.test.ts +++ b/src/agent/directors/registry.test.ts @@ -50,7 +50,7 @@ describe("director registry", () => { test("intent map defaults (no general)", () => { expect(resolveDirector({ intent: "implement" })).toMatchObject({ ok: true, - package: { id: "implement" }, + package: { id: "build" }, }); expect(resolveDirector({ intent: "explore" })).toMatchObject({ ok: true, @@ -154,8 +154,8 @@ describe("director registry", () => { } }); - test("implement mounts product writes; intern is shell-only; other leaves do not spawn", () => { - expect(DIRECTOR_REGISTRY.implement.tools?.allow).toEqual( + test("build mounts product writes; intern is shell-only; other leaves do not spawn", () => { + expect(DIRECTOR_REGISTRY.build.tools?.allow).toEqual( expect.arrayContaining(["write_file", "edit_file", "delete_file"]), ); const internAllow = DIRECTOR_REGISTRY.intern.tools?.allow ?? []; diff --git a/src/agent/directors/registry.ts b/src/agent/directors/registry.ts index a1ef361c0..fa2289e0c 100644 --- a/src/agent/directors/registry.ts +++ b/src/agent/directors/registry.ts @@ -7,7 +7,7 @@ import { emilPackage } from "./emil/index.js"; import { explorePackage } from "./explore/index.js"; import { gaasbotPackage } from "./gaasbot/index.js"; import { greybeardPackage } from "./greybeard/index.js"; -import { implementPackage } from "./implement/index.js"; +import { buildDirectorPackage } from "./build/index.js"; import { internPackage } from "./intern/index.js"; import { neckbeardPackage } from "./neckbeard/index.js"; import { planPackage } from "./plan/index.js"; @@ -27,7 +27,7 @@ import { /** Intent → default director when `task(agent=…)` is omitted. No general director. */ export const INTENT_DEFAULT_DIRECTOR: Readonly, DirectorId>> = { - implement: "implement", + implement: "build", explore: "explore", plan: "plan", review: "critique", @@ -39,7 +39,7 @@ export const INTENT_DEFAULT_DIRECTOR: Readonly> = { skywalker: skywalkerPackage, - implement: implementPackage, + build: buildDirectorPackage, explore: explorePackage, plan: planPackage, intern: internPackage, diff --git a/src/agent/directors/skywalker/package.test.ts b/src/agent/directors/skywalker/package.test.ts index f38a973d5..e546affa6 100644 --- a/src/agent/directors/skywalker/package.test.ts +++ b/src/agent/directors/skywalker/package.test.ts @@ -24,7 +24,7 @@ describe("skywalkerPackage", () => { expect(skywalkerPackage.spawn.maySpawn).toBe(true); expect(skywalkerPackage.spawn.allowlist).toHaveLength(15); expect(skywalkerPackage.spawn.allowlist).toEqual([ - "implement", + "build", "explore", "plan", "intern", diff --git a/src/agent/directors/skywalker/package.ts b/src/agent/directors/skywalker/package.ts index 911c23248..7109a2d8d 100644 --- a/src/agent/directors/skywalker/package.ts +++ b/src/agent/directors/skywalker/package.ts @@ -23,7 +23,7 @@ Example chains: - feature: explore → implement → critique - "why / how / is this stalled": answer yourself; at most one explore if a single unknown blocks you -Closed directors (use search_agents / registry; each id matches task(agent="")): implement, explore, plan, intern, critique, greybeard, neckbeard, bruckheimer, gaasbot, draper, emil, brand-reviewer, shakespeare, testsmith, tester. +Closed directors (use search_agents / registry; each id matches task(agent="")): build, explore, plan, intern, critique, greybeard, neckbeard, bruckheimer, gaasbot, draper, emil, brand-reviewer, shakespeare, testsmith, tester. No catch-all worker. If unsure, reclassify — do not spawn a blob agent. Quick routing: @@ -131,7 +131,7 @@ Do not reclassify COMMUNICATION as ORCHESTRATION just to justify parallel task s # Spawn graph Skywalker = full closed set. Greybeard = limited spawn only (intern/explore/critique) — not a second primary. -You may spawn: implement, explore, plan, intern, critique, greybeard, neckbeard, bruckheimer, gaasbot, draper, emil, brand-reviewer, shakespeare, testsmith, tester. +You may spawn: build, explore, plan, intern, critique, greybeard, neckbeard, bruckheimer, gaasbot, draper, emil, brand-reviewer, shakespeare, testsmith, tester. When spawning, prefer a typed brief: - intent — explore | implement | plan | review @@ -174,7 +174,7 @@ export const skywalkerPackage: DirectorPackage = { spawn: { maySpawn: true, allowlist: [ - "implement", + "build", "explore", "plan", "intern", diff --git a/src/agent/directors/tool-sets.test.ts b/src/agent/directors/tool-sets.test.ts index c5baf5b6c..74e443814 100644 --- a/src/agent/directors/tool-sets.test.ts +++ b/src/agent/directors/tool-sets.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; import { DOCS_TOOLS, - IMPLEMENT_TOOLS, + BUILD_TOOLS, ORCHESTRATOR_TOOLS, READ_TOOLS, SKYWALKER_TOOLS, @@ -31,7 +31,7 @@ describe("DOCS_TOOLS", () => { }); test("run_shell stays on the other surfaces", () => { - for (const surface of [READ_TOOLS, IMPLEMENT_TOOLS]) { + for (const surface of [READ_TOOLS, BUILD_TOOLS]) { expect(surface).toContain("run_shell"); } }); diff --git a/src/agent/directors/tool-sets.ts b/src/agent/directors/tool-sets.ts index 1c73604da..42cc41f4a 100644 --- a/src/agent/directors/tool-sets.ts +++ b/src/agent/directors/tool-sets.ts @@ -16,8 +16,8 @@ export const READ_TOOLS = [ "web_search", ] as const; -/** Implement: read + full file mutation. */ -export const IMPLEMENT_TOOLS = [ +/** Build: read + full file mutation. */ +export const BUILD_TOOLS = [ ...READ_TOOLS, "write_file", "edit_file", diff --git a/src/agent/directors/types.ts b/src/agent/directors/types.ts index cf51462b5..78f7cb5fe 100644 --- a/src/agent/directors/types.ts +++ b/src/agent/directors/types.ts @@ -3,7 +3,7 @@ export const DIRECTOR_IDS = [ "skywalker", - "implement", + "build", "explore", "plan", "intern", diff --git a/src/config.test.ts b/src/config.test.ts index b0ef2c75b..fec1d0ca4 100644 --- a/src/config.test.ts +++ b/src/config.test.ts @@ -184,16 +184,16 @@ describe("loadConfig", () => { } }); - test("parses exec --director implement", async () => { + test("parses exec --director build", async () => { const cwd = await emptyCwd(); try { const globalPath = await writeGlobalSettings(cwd); - const config = await loadConfig(["exec", "--cwd", cwd, "--director", "implement", "ship it"], { + const config = await loadConfig(["exec", "--cwd", cwd, "--director", "build", "ship it"], { globalSettingsPath: globalPath, }); assertConfigured(config); expect(config.command).toBe("exec"); - expect(config.director).toBe("implement"); + expect(config.director).toBe("build"); expect(config.task).toBe("ship it"); } finally { await rm(cwd, { recursive: true, force: true }); @@ -221,6 +221,14 @@ describe("loadConfig", () => { ).rejects.toThrow(new RegExp(`Unknown director "nope".*${DIRECTOR_IDS.join(", ")}`)); }); + test("--director implement is unknown and lists closed-fleet ids including build", async () => { + await expect( + loadConfig(["exec", "--director", "implement", "ship it"], { globalSettingsPath: NO_SETTINGS }), + ).rejects.toThrow(new RegExp(`Unknown director "implement".*${DIRECTOR_IDS.join(", ")}`)); + expect(DIRECTOR_IDS).toContain("build"); + expect(DIRECTOR_IDS).not.toContain("implement"); + }); + test("--director without a value errors", async () => { await expect(loadConfig(["exec", "--director"], { globalSettingsPath: NO_SETTINGS })).rejects.toThrow( "--director requires a value", diff --git a/tests/unit/exec/runner.test.ts b/tests/unit/exec/runner.test.ts index d45ea99c1..6f791d4d7 100644 --- a/tests/unit/exec/runner.test.ts +++ b/tests/unit/exec/runner.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; import type { Config } from "../../../src/config/index.js"; import { formatCaughtError, resolveExecDirectorOverlay, runExec } from "../../../src/exec/runner.js"; -import { IMPLEMENT_TOOLS } from "../../../src/agent/directors/tool-sets.js"; +import { BUILD_TOOLS } from "../../../src/agent/directors/tool-sets.js"; function bareConfig(task: string): Config { // Minimal unconfigured-shaped object is not enough — runExec only needs @@ -51,12 +51,12 @@ describe("runExec", () => { }); describe("resolveExecDirectorOverlay", () => { - test("implement exec primary does not mount task", () => { - const overlay = resolveExecDirectorOverlay("implement"); + test("build exec primary does not mount task", () => { + const overlay = resolveExecDirectorOverlay("build"); expect(overlay.mountTask).toBe(false); expect(overlay.advertisedAllow).toBeDefined(); expect(overlay.advertisedAllow).not.toContain("task"); - expect(overlay.advertisedAllow).toEqual([...IMPLEMENT_TOOLS]); + expect(overlay.advertisedAllow).toEqual([...BUILD_TOOLS]); expect(overlay.systemPrompt).toContain("ImplementDirector"); }); From e6ed73c62307b2f0819a221676e4dc528e9c65f5 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sat, 22 Aug 2026 00:49:46 -0700 Subject: [PATCH 2/6] Point Skywalker spawn targets at the build director --- CHANGELOG.md | 5 ++ .../corbits-skills/skills/dispatch/SKILL.md | 46 +++++++++---------- .../corbits-skills/skills/implement/SKILL.md | 16 +++---- .../skills/linear-issue-workflow/SKILL.md | 14 +++--- plugins/corbits-skills/skills/opsh/SKILL.md | 4 +- src/agent/directors/skywalker/package.test.ts | 16 ++++++- src/agent/directors/skywalker/package.ts | 15 +++--- src/agent/prompts.ts | 2 +- src/subagent/task-tool.ts | 2 +- tests/unit/subagent.test.ts | 4 +- 10 files changed, 71 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e905a285..d30c8c78b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,11 @@ parallel copies under `docs/` or `scripts/notes/`. At cut time: rename ### Directors +- **Skywalker spawn-target for product code is `build`.** Prompt and + skill copy that still said `spawn implement` / `task(agent="implement")` + now dispatch `build`. Intent graph `explore → implement → critique` + and slash `/implement` are unchanged. + - **Skywalker may DIY tiny product writes (CL-6629).** Path tools (`write_file` / `edit_file` / `delete_file`) remount on the primary session. Tiny/single-file/one-route bounded edits are the exception; diff --git a/plugins/corbits-skills/skills/dispatch/SKILL.md b/plugins/corbits-skills/skills/dispatch/SKILL.md index c3127f5b1..434f54205 100644 --- a/plugins/corbits-skills/skills/dispatch/SKILL.md +++ b/plugins/corbits-skills/skills/dispatch/SKILL.md @@ -2,18 +2,18 @@ name: dispatch user-invocable: false argument-hint: "[ | dispatch// | dispatch//dispatch.yaml | ]" -description: Multi-lane DAG orchestration. Skywalker recipe — use_skill("dispatch"). Spawns explore, intern, implement, plan, and critique. DAG product tasks go through implement; Skywalker may DIY tiny edits outside the DAG. +description: Multi-lane DAG orchestration. Skywalker recipe — use_skill("dispatch"). Spawns explore, intern, build, plan, and critique. DAG product tasks go through build; Skywalker may DIY tiny edits outside the DAG. --- # Dispatch -You are Skywalker. This skill is loadable with `use_skill("dispatch")`. Follow this recipe. DAG product tasks go through implement workers. Do not write `dispatch.yaml` or `plan.md` yourself (intern cannot write; implement writes manifests). Tiny / single-file / one-route product edits outside this DAG may be DIY with write_file/edit_file/delete_file. +You are Skywalker. This skill is loadable with `use_skill("dispatch")`. Follow this recipe. DAG product tasks go through build workers. Do not write `dispatch.yaml` or `plan.md` yourself (intern cannot write; build writes manifests). Tiny / single-file / one-route product edits outside this DAG may be DIY with write_file/edit_file/delete_file. Orchestrate parallel director runs across a dependency graph. Fan out work, fan in reports, critique, verify, re-dispatch fixes, and synthesize until done. Hard cap: **at most 4 workers at once** unless the operator explicitly asks for a wider fan-out. Track progress with `manage_tasks`. -Closed directors used here: `explore`, `intern`, `implement`, `plan`, `critique`. Optional consults: `greybeard`, `tester`. Never a catch-all worker. DAG node agents are `explore`, `intern`, and `implement` only. +Closed directors used here: `explore`, `intern`, `build`, `plan`, `critique`. Optional consults: `greybeard`, `tester`. Never a catch-all worker. DAG node agents are `explore`, `intern`, and `build` only. ## Input resolution @@ -33,13 +33,13 @@ If the spec is vague, incomplete, or contradictory: stop and report Blockers. Do |---|---| | Map the codebase, gather facts | `task(agent="explore")` | | Eng plan from a spec (no ship) | `task(agent="plan")` | -| Write `dispatch.yaml` / `plan.md` / status artifacts (mechanical brief; no product feature work) | `task(agent="implement")` | -| Ship product code + tests | `task(agent="implement")` | +| Write `dispatch.yaml` / `plan.md` / status artifacts (mechanical brief; no product feature work) | `task(agent="build")` | +| Ship product code + tests | `task(agent="build")` | | Review a landed task (defects, evidence, no fix) | `task(agent="critique")` | | Architecture judgment before a large DAG | `task(agent="greybeard")` | | Independent suite / repro evidence | `task(agent="tester")` | -Skywalker classifies, spawns, tracks, and synthesizes. Path tools (`write_file` / `edit_file` / `delete_file`) are mounted for DIY tiny/bounded product edits; spawn remains the default for DAG product work. Durable orchestration artifacts (`dispatch.yaml`, `plan.md`, status) still go through implement — intern does not have write tools (`INTERN_TOOLS` = run_shell, read_file, list_dir). Do not spawn a blob agent to author the manifest. Do not write those manifests on Skywalker. +Skywalker classifies, spawns, tracks, and synthesizes. Path tools (`write_file` / `edit_file` / `delete_file`) are mounted for DIY tiny/bounded product edits; spawn remains the default for DAG product work. Durable orchestration artifacts (`dispatch.yaml`, `plan.md`, status) still go through build — intern does not have write tools (`INTERN_TOOLS` = run_shell, read_file, list_dir). Do not spawn a blob agent to author the manifest. Do not write those manifests on Skywalker. Prefer typed briefs: `intent`, `success_criteria`, `do_not`, `report_focus`, and `agent`. @@ -49,9 +49,9 @@ Use **explore** when the task is pure research. No code changes. Output is findi Use **intern** when the work is mechanical and well-specified: git commit after a level fans in, exact shell, mechanical git. Intern cannot write files. -Use **implement** when the task ships product code — including work that needs judgment, new abstractions, or tests — and for mechanical writes of `dispatch.yaml` / `plan.md` / status artifacts (write tools; intern does not have them). There is no catch-all implementation agent. +Use **build** when the task ships product code — including work that needs judgment, new abstractions, or tests — and for mechanical writes of `dispatch.yaml` / `plan.md` / status artifacts (write tools; intern does not have them). There is no catch-all implementation agent. -Critique is not a DAG node agent type. After implement (and after non-trivial intern landings), spawn `task(agent="critique")` with the task's objective, paths, and diff. Simple intern tasks may skip critique. +Critique is not a DAG node agent type. After build (and after non-trivial intern landings), spawn `task(agent="critique")` with the task's objective, paths, and diff. Simple intern tasks may skip critique. Classify each product task as `feature` or `bugfix`: @@ -61,25 +61,25 @@ Classify each product task as `feature` or `bugfix`: ## Phase 1: Planning -Runs when the input is a spec (or a request with no existing manifest). The spec should be complete enough that an implement worker could succeed from it. +Runs when the input is a spec (or a request with no existing manifest). The spec should be complete enough that a build worker could succeed from it. 1. If the spec still needs an ordered eng plan, spawn `task(agent="plan")`. Do not skip this when requirements are large or ambiguous. 2. Spawn `explore` workers only as needed to map scope. Distinct path/package lenses if parallel. 3. Consult `greybeard` before large multi-lane work when architecture is in play. 4. Break the goal into discrete tasks, each small enough for one director. 5. Identify dependencies (DAG edges). Same-file writers at the same level must be merged or serialized via `depends-on`. -6. Assign `explore` | `intern` | `implement` per the guide above. +6. Assign `explore` | `intern` | `build` per the guide above. 7. Detect verify commands from `package.json`, Makefile, or project docs. 8. Add per-task verification to each plan (build for compiled changes, tests for test-writing tasks). 9. Default commit strategy is **per-task** (debuggable). Use grouped only when the operator wants a cleaner history **and** Phase 5 will catch issues. -10. Mark which tasks need critique (complex implement → yes; simple intern → no; when unsure, yes). +10. Mark which tasks need critique (complex build → yes; simple intern → no; when unsure, yes). 11. Seed `manage_tasks` with one item per DAG task (plus plan / verify / critique items as needed). -If requirements are not actionable, stop. Ask: "Can an implement worker succeed with only this information?" +If requirements are not actionable, stop. Ask: "Can a build worker succeed with only this information?" ## Phase 2: Directory structure -Have **implement** write the run tree (mechanical brief; no product feature work). Do not write these files on Skywalker. Do not use intern — intern cannot write files. Do not use a catch-all worker. +Have **build** write the run tree (mechanical brief; no product feature work). Do not write these files on Skywalker. Do not use intern — intern cannot write files. Do not use a catch-all worker. ``` dispatch/ @@ -125,7 +125,7 @@ commits: tasks: - id: 1a-extract_auth_module type: feature # feature | bugfix (omit for explore) - agent: implement # implement | intern | explore + agent: build # build | intern | explore depends-on: [] receives: [] # subset of depends-on; default = depends-on status: pending # pending | dispatched | completed | failed | fixing @@ -134,7 +134,7 @@ tasks: - id: 2a-integrate_modules type: feature - agent: implement + agent: build depends-on: [1a-extract_auth_module, 1b-extract_logging_module] status: pending ``` @@ -143,7 +143,7 @@ Task statuses: `pending` → `dispatched` → `completed` | `failed` | `fixing`. ### Task `plan.md` -Implement writes one per task (mechanical brief). Include: objective, requirements covered, context (paths and symbols — no line numbers, no dispatch-dir cross-refs), files to modify, constraints, verification (test-first for bugfix), and `do_not`. +Build writes one per task (mechanical brief). Include: objective, requirements covered, context (paths and symbols — no line numbers, no dispatch-dir cross-refs), files to modify, constraints, verification (test-first for bugfix), and `do_not`. Every product-task brief must tell the worker: @@ -165,16 +165,16 @@ Before any product spawn: Empty task list → mark the run `completed` and report. Do not invent work. -Present the DAG (ids, agents, deps, critique flags, verify commands, commit strategy) to the operator. Wait for go-ahead on large or ambiguous runs. Then set status `in-progress` (implement updates the manifest if it is on disk). +Present the DAG (ids, agents, deps, critique flags, verify commands, commit strategy) to the operator. Wait for go-ahead on large or ambiguous runs. Then set status `in-progress` (build updates the manifest if it is on disk). ## Phase 4: Execute the DAG 1. **Ready set:** `pending` tasks whose `depends-on` are all `completed`. 2. **Batch:** take a safe parallel subset, **at most 4 live workers** (including in-flight critique). Same-file writers and shared mutable state (build artifacts, test DBs) must not share a batch — serialize with `depends-on`. -3. **Spawn** each task with `task(agent="")`. Inject upstream reports (not a rewritten `plan.md`) into the brief. Split ownership by path/package when two implement workers run together. -4. **Fan in:** trust the worker report (and `output.yaml` when implement wrote one). Missing report or `status: failed` → mark `failed`. Do not re-fan-out an identical brief; change `success_criteria` / `do_not` or tell the operator. +3. **Spawn** each task with `task(agent="")`. Inject upstream reports (not a rewritten `plan.md`) into the brief. Split ownership by path/package when two build workers run together. +4. **Fan in:** trust the worker report (and `output.yaml` when build wrote one). Missing report or `status: failed` → mark `failed`. Do not re-fan-out an identical brief; change `success_criteria` / `do_not` or tell the operator. 5. **Level commit:** after a level's product tasks self-report complete, intern commits per the strategy (per-task default). Workers must not have committed. -6. **Critique:** for tasks with `critique.enabled`, spawn `task(agent="critique")` on that commit/diff + objective. Blocking findings → re-dispatch `implement` with those findings in `success_criteria` / `do_not` (status `fixing`). Cap re-fix rounds (1–2), then report Blockers. +6. **Critique:** for tasks with `critique.enabled`, spawn `task(agent="critique")` on that commit/diff + objective. Blocking findings → re-dispatch `build` with those findings in `success_criteria` / `do_not` (status `fixing`). Cap re-fix rounds (1–2), then report Blockers. 7. Repeat until no pending tasks remain, or deadlock / all remaining failed → stop and ask. Keep `manage_tasks` in sync as items move `todo` → `doing` → `done` / stay blocked. @@ -186,7 +186,7 @@ If the working tree has unrelated uncommitted changes before Phase 4, ask the op Must `task(agent="tester")` for the suite (or intern for one named mechanical command). Do not run the full verify pipeline on the parent via Skywalker `run_shell`. Compare against any baseline you captured. - Green, or same failures as baseline → proceed. -- New failures → attribute to a task/commit, re-dispatch `implement` on that lane, re-verify. Cap rounds, then Blockers. +- New failures → attribute to a task/commit, re-dispatch `build` on that lane, re-verify. Cap rounds, then Blockers. - Do not declare done on a worker "ready" that ignored blocking critique or verify. ## Phase 6: Complete @@ -206,8 +206,8 @@ Re-resolve input to the existing `dispatch//`. Re-validate the remaining D ## Non-negotiables -- You are Skywalker. Spawn directors. Do not implement product features. Do not author dispatch YAML/plan files yourself or via a catch-all worker. Durable orchestration files go through implement. +- You are Skywalker. Spawn directors. Do not implement product features. Do not author dispatch YAML/plan files yourself or via a catch-all worker. Durable orchestration files go through build. - `use_skill("dispatch")` loads this recipe. It is a command. -- Agents: `explore`, `intern`, `implement` only for DAG nodes. Critique via `task(agent="critique")`. Plan via `task(agent="plan")` when a spec needs an eng plan first. +- Agents: `explore`, `intern`, `build` only for DAG nodes. Critique via `task(agent="critique")`. Plan via `task(agent="plan")` when a spec needs an eng plan first. - Progress: `manage_tasks`. - At most 4 workers at once unless the operator asks for more. diff --git a/plugins/corbits-skills/skills/implement/SKILL.md b/plugins/corbits-skills/skills/implement/SKILL.md index e9deef6ce..70b3648f3 100644 --- a/plugins/corbits-skills/skills/implement/SKILL.md +++ b/plugins/corbits-skills/skills/implement/SKILL.md @@ -1,6 +1,6 @@ --- name: implement -description: Disciplined per-commit workflow — Skywalker spawns greybeard, implement, intern/tester, critique. +description: Disciplined per-commit workflow — Skywalker spawns greybeard, build, intern/tester, critique. --- # Implement @@ -26,7 +26,7 @@ Track commit-sized units with `manage_tasks`. One item per unit that will become ## Per-commit spawn loop -For each unit, run these steps in order. Do not skip. When this loop is running, do not DIY the unit — spawn implement. +For each unit, run these steps in order. Do not skip. When this loop is running, do not DIY the unit — spawn build. ### 1. Review — greybeard @@ -38,18 +38,18 @@ Send: - Design decisions and trade-offs - Uncertainties -Adjust the plan from the report, then spawn implement. Greybeard is for approach, not execution. +Adjust the plan from the report, then spawn build. Greybeard is for approach, not execution. ### 2. Implement -`task(agent="implement")` with a typed brief: +`task(agent="build")` with a typed brief: - `intent` - `success_criteria` - `do_not` - `report_focus` -**Bug fixes:** tell implement to start from a failing test — write the repro, confirm it fails, then fix, then confirm it passes. If the test does not fail first, the bug is not understood. +**Bug fixes:** tell build to start from a failing test — write the repro, confirm it fails, then fix, then confirm it passes. If the test does not fail first, the bug is not understood. **Features:** tests ship with the change. The test asserts the new behavior, not merely that the process did not crash. @@ -62,20 +62,20 @@ Keep scope to this unit. Additional work becomes a later `manage_tasks` item, no - `intern` — mechanical full pipeline - `tester` — suite / repro -Do not move forward with a broken build. If failures come from this unit, re-dispatch implement. If they are pre-existing and unrelated, report Blockers and stop. Do not substitute a partial compile for the full gate. +Do not move forward with a broken build. If failures come from this unit, re-dispatch build. If they are pre-existing and unrelated, report Blockers and stop. Do not substitute a partial compile for the full gate. ### 4. Critique `task(agent="critique")` on the diff. Include the intent agreed with greybeard so critique evaluates plan vs execution, not only surface quality. Limit findings to this unit; pre-existing issues in touched files are out of scope unless they block the gate. -If critique is **blocking**, re-dispatch implement once or twice with those findings in `success_criteria` / `do_not`, then re-run the build gate and critique. After two re-fix rounds, report Blockers — do not loop forever. +If critique is **blocking**, re-dispatch build once or twice with those findings in `success_criteria` / `do_not`, then re-run the build gate and critique. After two re-fix rounds, report Blockers — do not loop forever. When critique is clean (or remaining findings are acknowledged judgment calls), mark the unit done and start the next. ## Hard rules - Tiny / single-file / one-route / clear bounded edits: DIY with write_file/edit_file/delete_file. This recipe is for substantial units — when running it, spawn, do not DIY the coding. -- Spawn with `task(agent="greybeard")`, `task(agent="implement")`, `task(agent="intern")` or `task(agent="tester")`, and `task(agent="critique")`. +- Spawn with `task(agent="greybeard")`, `task(agent="build")`, `task(agent="intern")` or `task(agent="tester")`, and `task(agent="critique")`. - Track only with `manage_tasks`. - Do not shortcut the loop. Skipping greybeard “because this is simple” or skipping critique “because the build passed” defeats the recipe. - Build must pass before treating a unit as done. diff --git a/plugins/corbits-skills/skills/linear-issue-workflow/SKILL.md b/plugins/corbits-skills/skills/linear-issue-workflow/SKILL.md index a5277e9ff..de091989c 100644 --- a/plugins/corbits-skills/skills/linear-issue-workflow/SKILL.md +++ b/plugins/corbits-skills/skills/linear-issue-workflow/SKILL.md @@ -1,7 +1,7 @@ --- name: linear-issue-workflow user-invocable: false -description: Skywalker implements a Linear issue by fetching it via MCP then running the /implement spawn loop. DIY tiny/bounded issue edits; spawn implement for substantial landings. +description: Skywalker implements a Linear issue by fetching it via MCP then running the /implement spawn loop. DIY tiny/bounded issue edits; spawn build for substantial landings. argument-hint: " [--reviewer ]" --- @@ -40,7 +40,7 @@ If intern fails, stop and `ask_operator`. If the operator rejects the issue befo 3. If the operator rejects the plan and the issue cannot be salvaged, intern tears down the worktree (Phase 7) rather than leaving it stranded. 4. Attach the plan to the Linear issue. **Do not post the plan as a comment** — comments are for discussion, not archives. - Spawn `task(agent="implement")` with a mechanical brief to write the approved plan to the worktree's `tmp/plan-.md` (do not commit it). Intern captures byte size with `wc -c`. Primary then: + Spawn `task(agent="build")` with a mechanical brief to write the approved plan to the worktree's `tmp/plan-.md` (do not commit it). Intern captures byte size with `wc -c`. Primary then: 1. `mcp__linear__prepare_attachment_upload` with `issue`, `filename`, `contentType: "text/markdown"`, and `size`. Response contains `uploadRequest.url`, `uploadRequest.headers`, and `assetUrl`. The signed URL expires in 60 seconds. 2. Intern PUTs the raw file bytes to `uploadRequest.url` via `run_shell`, every header from `uploadRequest.headers` verbatim (exact casing). Do not base64-encode. If PUT returns 403 because the URL expired, prepare a fresh URL and retry once. @@ -55,15 +55,15 @@ If intern fails, stop and `ask_operator`. If the operator rejects the issue befo Do not implement on Skywalker. For each commit-sized unit, run `/implement`: 1. `task(agent="greybeard")` on the approach before any code is written. -2. `task(agent="implement")` with a typed brief (`intent`, `success_criteria`, `do_not`, `report_focus`) and the absolute worktree path. Bug fixes start from a failing test. Features ship tests with the change. +2. `task(agent="build")` with a typed brief (`intent`, `success_criteria`, `do_not`, `report_focus`) and the absolute worktree path. Bug fixes start from a failing test. Features ship tests with the change. 3. `task(agent="intern")` or `task(agent="tester")` for the project build/test gate. -4. `task(agent="critique")` on the diff. Blocking findings → re-dispatch implement (cap two re-fix rounds), then re-run the gate and critique. +4. `task(agent="critique")` on the diff. Blocking findings → re-dispatch build (cap two re-fix rounds), then re-run the gate and critique. Track units with `manage_tasks`. Copy style/philosophy into worker briefs (`use_skill` on the primary before spawning; workers do not mount `use_skill`). ### Checkboxes -If the issue description contains a task list (`- [ ]` items), tick boxes as implement reports each one complete. Update with `mcp__linear__save_issue`, passing the full description with only the relevant `- [ ]` flipped to `- [x]`. Do not rewrite surrounding text. If there is no task list, skip — do not invent one. +If the issue description contains a task list (`- [ ]` items), tick boxes as build reports each one complete. Update with `mcp__linear__save_issue`, passing the full description with only the relevant `- [ ]` flipped to `- [x]`. Do not rewrite surrounding text. If there is no task list, skip — do not invent one. ## Phase 5: Branch review @@ -154,7 +154,7 @@ If the worktree directory was already deleted: `git worktree prune`. ## Hard rules -- Tiny / single-file / one-route / clear bounded edits: DIY with write_file/edit_file/delete_file. Substantial issue landings: spawn implement (this recipe). -- Spawn with `task(agent="greybeard")`, `task(agent="implement")`, `task(agent="intern")` or `task(agent="tester")`, and `task(agent="critique")`. +- Tiny / single-file / one-route / clear bounded edits: DIY with write_file/edit_file/delete_file. Substantial issue landings: spawn build (this recipe). +- Spawn with `task(agent="greybeard")`, `task(agent="build")`, `task(agent="intern")` or `task(agent="tester")`, and `task(agent="critique")`. - Clarifying questions use `ask_operator`. - Shell is `run_shell`, not a Bash tool. diff --git a/plugins/corbits-skills/skills/opsh/SKILL.md b/plugins/corbits-skills/skills/opsh/SKILL.md index 8ef14edc6..83054a9f6 100644 --- a/plugins/corbits-skills/skills/opsh/SKILL.md +++ b/plugins/corbits-skills/skills/opsh/SKILL.md @@ -6,9 +6,9 @@ description: Write scripts using opsh and its built-in libraries. Tiny scripts: # opsh Scripting -You are Skywalker. Host is Corbits Code. This is a convention skill. Tiny / single-file scripts: DIY with write_file/edit_file using these rules. Substantial script work: spawn implement with this skill's rules copied into the brief (workers do not mount `use_skill`). +You are Skywalker. Host is Corbits Code. This is a convention skill. Tiny / single-file scripts: DIY with write_file/edit_file using these rules. Substantial script work: spawn build with this skill's rules copied into the brief (workers do not mount `use_skill`). -If the operator wants a substantial script written, spawn `task(agent="implement")` with this skill's rules copied into the brief. If the operator wants a review, spawn `task(agent="critique")` (or `task(agent="neckbeard")` for hygiene-only) with the same rules copied in. +If the operator wants a substantial script written, spawn `task(agent="build")` with this skill's rules copied into the brief. If the operator wants a review, spawn `task(agent="critique")` (or `task(agent="neckbeard")` for hygiene-only) with the same rules copied in. Shell for agent commands is `run_shell` (there is no Bash tool). Bash-the-language in the examples below stays — opsh scripts are bash. diff --git a/src/agent/directors/skywalker/package.test.ts b/src/agent/directors/skywalker/package.test.ts index e546affa6..d26ac10f5 100644 --- a/src/agent/directors/skywalker/package.test.ts +++ b/src/agent/directors/skywalker/package.test.ts @@ -95,6 +95,7 @@ describe("skywalkerPackage", () => { expect(p).toContain("long-blocking"); expect(p).toContain("tool.boundary"); expect(p).toContain("Dispatch intern"); + expect(p).toContain("or build (substantial code)"); }); test("systemPrompt has effort scaling / fan-out ladder", () => { @@ -164,10 +165,21 @@ describe("skywalkerPackage", () => { expect(p).toContain("correctness/brief gaps"); }); - test("systemPrompt re-dispatches implement on blocking critique", () => { + test("systemPrompt spawn-target for substantial code is build, not implement", () => { + const p = skywalkerPackage.systemPrompt; + expect(p).toContain("spawn build"); + expect(p).toContain("spawn (build for code"); + expect(p).toContain("build = ship product code + tests"); + expect(p).not.toMatch(/\bspawn implement\b/); + expect(p).toContain("explore → implement → critique"); + expect(p).toContain("Do not always explore→implement→critique"); + expect(p).toContain("implement = ship product code + tests"); + }); + + test("systemPrompt re-dispatches build on blocking critique", () => { const p = skywalkerPackage.systemPrompt; expect(p).toContain("blocking"); - expect(p).toContain("re-dispatch"); + expect(p).toContain("re-dispatch **build**"); expect(p).toContain("ship → verify → fix → re-verify"); expect(p).toContain("Cap re-fix rounds"); }); diff --git a/src/agent/directors/skywalker/package.ts b/src/agent/directors/skywalker/package.ts index 7109a2d8d..555b08b51 100644 --- a/src/agent/directors/skywalker/package.ts +++ b/src/agent/directors/skywalker/package.ts @@ -14,7 +14,7 @@ You do not do the specialists' jobs by default. For tiny bounded product edits, # Parent tools -Do not run long-blocking jobs on the parent (evals, full test suites, long installs, long-running implementation). Dispatch intern (mechanical shell), tester (suite / repro), or implement (substantial code). Path tools (write_file/edit_file/delete_file) are the DIY surface; shell file-writes stay denied. +Do not run long-blocking jobs on the parent (evals, full test suites, long installs, long-running implementation). Dispatch intern (mechanical shell), tester (suite / repro), or build (substantial code). Path tools (write_file/edit_file/delete_file) are the DIY surface; shell file-writes stay denied. task() still awaits the worker's full report. Enter mid-run delivers at the next parent tool.boundary — a long parent run_shell or awaiting task() holds those steers. Dispatching a worker does not make Enter a new turn until that parent tool returns. @@ -29,6 +29,7 @@ No catch-all worker. If unsure, reclassify — do not spawn a blob agent. Quick routing: - explore = map/read codebase - plan = ordered eng plan (no ship) +- build = ship product code + tests - implement = ship product code + tests - critique = defects with evidence (no fix) - greybeard = architecture judgment @@ -42,7 +43,7 @@ Quick routing: - gaasbot = risk counsel - bruckheimer = product discovery docs - intern = exact shell / mechanical ops -- After multi-file implement landings → default a critique (or greybeard when architecture is in play) on the diff/criteria in a fresh context +- After multi-file build landings → default a critique (or greybeard when architecture is in play) on the diff/criteria in a fresh context Prefer typed spawn: intent, success_criteria, do_not, report_focus, agent when specialist. Parallelize independent lanes. manage_tasks for your checklist. ask_operator when blocked or ambiguous. @@ -51,7 +52,7 @@ Parallelize independent lanes. manage_tasks for your checklist. ask_operator whe When the operator (or brief) gives an http(s) URL to read: - Call **web_fetch** yourself on that URL — it is already mounted. Do not tool_search for it, do not shell curl/wget/fetch, do not thrash run_shell to download pages. -- After you have the content, DIY a tiny file write yourself; spawn implement only if the write is substantial. For pure Q&A from a URL, answer directly. +- After you have the content, DIY a tiny file write yourself; spawn build only if the write is substantial. For pure Q&A from a URL, answer directly. - Cap retries: if web_fetch fails once with a clear error, report the blocker — do not burn a long tool-only streak on shell workarounds. # Effort scaling (IMPLEMENTATION / ORCHESTRATION) @@ -81,8 +82,8 @@ When the operator brief states a function signature or return shape, put that ** # Verify after ship -Multi-file or public-API changes: after implement, run **critique** focused on brief + public API contract (sync/async, signatures). Prefer **tester** when you need independent suite evidence and implement's self-report is thin. -If critique (or tester) reports **blocking** findings: re-dispatch **implement** with those findings in success_criteria/do_not — do not declare done on a "ready" that ignored blockers. +Multi-file or public-API changes: after build, run **critique** focused on brief + public API contract (sync/async, signatures). Prefer **tester** when you need independent suite evidence and build's self-report is thin. +If critique (or tester) reports **blocking** findings: re-dispatch **build** with those findings in success_criteria/do_not — do not declare done on a "ready" that ignored blockers. Close the loop: ship → verify → fix → re-verify. Cap re-fix rounds (e.g. 1–2) then report Blockers. Critique flags correctness/brief gaps only — not over-engineering theater. @@ -98,7 +99,7 @@ Before responding, classify: Tiny / single-file / one-route / clear bounded edit: write_file/edit_file/delete_file on this session. Do not spawn. -Substantial / multi-file / parallel lanes / long-running: spawn implement (hard cap 4). Keep long-blocking jobs off the parent so Enter can steer. +Substantial / multi-file / parallel lanes / long-running: spawn build (hard cap 4). Keep long-blocking jobs off the parent so Enter can steer. Docs/design (PRODUCT.md, ARCHITECTURE.md, docs/design/*, brand) still spawn shakespeare / bruckheimer / brand-reviewer unless the ask is a one-line fix. @@ -121,7 +122,7 @@ Do not reclassify COMMUNICATION as ORCHESTRATION just to justify parallel task s # Non-negotiables -- Tiny/single-file/one-route product edits: write_file/edit_file/delete_file yourself. Substantial, multi-file, parallel, or specialist work: spawn (implement for code; shakespeare / bruckheimer / brand-reviewer for docs/design unless a one-line fix). +- Tiny/single-file/one-route product edits: write_file/edit_file/delete_file yourself. Substantial, multi-file, parallel, or specialist work: spawn (build for code; shakespeare / bruckheimer / brand-reviewer for docs/design unless a one-line fix). - Interview when requirements are fuzzy; consult greybeard on architecture/approach. - Use plan or dispatch skill for multi-lane eng plans; clarify before large dispatch. - Path tools are the DIY surface; shell file-writes stay denied. Track fleet work with manage_tasks. diff --git a/src/agent/prompts.ts b/src/agent/prompts.ts index d1a4b1020..a9ea04766 100644 --- a/src/agent/prompts.ts +++ b/src/agent/prompts.ts @@ -162,7 +162,7 @@ export function buildPromptDisciplineBlock(opts: { subAgent?: boolean } = {}): s const subAgent = opts.subAgent ?? false; const toolsOverShell = subAgent ? "- Never use run_shell to read, edit, or write files — use read_file, edit_file, write_file; cat/head/tail, sed/awk/perl -i, and heredoc/echo redirection are prohibited substitutes." - : "- Never use run_shell to read, edit, or write files — use read_file, edit_file, write_file for tiny/bounded DIY; spawn implement/docs directors for substantial work; cat/head/tail, sed/awk/perl -i, and heredoc/echo redirection are prohibited substitutes."; + : "- Never use run_shell to read, edit, or write files — use read_file, edit_file, write_file for tiny/bounded DIY; spawn build/docs directors for substantial work; cat/head/tail, sed/awk/perl -i, and heredoc/echo redirection are prohibited substitutes."; return [ "Prompt discipline:", "", diff --git a/src/subagent/task-tool.ts b/src/subagent/task-tool.ts index 24d5e2d3f..e1fc75278 100644 --- a/src/subagent/task-tool.ts +++ b/src/subagent/task-tool.ts @@ -451,7 +451,7 @@ export function createTaskTool(deps: TaskToolDeps): AgentTool { if (agentId === "skywalker" || resolvedDirectorId === "skywalker") { return taskToolResult( call.id, - "Error: skywalker is the primary session identity, not a spawned worker. Pass task(agent=…) for a specialist (implement, explore, plan, critique, …).", + "Error: skywalker is the primary session identity, not a spawned worker. Pass task(agent=…) for a specialist (build, explore, plan, critique, …).", ); } diff --git a/tests/unit/subagent.test.ts b/tests/unit/subagent.test.ts index 4db6644b8..906edda8f 100644 --- a/tests/unit/subagent.test.ts +++ b/tests/unit/subagent.test.ts @@ -213,7 +213,7 @@ test("closed director resolves without profiles loaded", async () => { const result = await callHandler(tool, { description: "ship", prompt: "implement the fix", - agent: "implement", + agent: "build", }); expect(result).toContain("ok"); expect(received?.systemPromptRole).toBeDefined(); @@ -305,7 +305,7 @@ test("spawnAllowlist rejects children outside the parent director matrix", async const denied = await callHandler(tool, { description: "ship code", prompt: "implement the feature", - agent: "implement", + agent: "build", }); expect(denied).toContain("Error:"); expect(denied).toContain("allowlist"); From 39fabec3587365c75585b7acd6f84c15b60fd30c Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sat, 22 Aug 2026 00:54:23 -0700 Subject: [PATCH 3/6] Say Spawn build in the primary harness facts --- plugins/corbits-skills/skills/pull-request-review/SKILL.md | 2 +- src/agent/prompts.ts | 4 ++-- src/prompts.test.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/corbits-skills/skills/pull-request-review/SKILL.md b/plugins/corbits-skills/skills/pull-request-review/SKILL.md index eb320ab0b..a9d9d81b4 100644 --- a/plugins/corbits-skills/skills/pull-request-review/SKILL.md +++ b/plugins/corbits-skills/skills/pull-request-review/SKILL.md @@ -101,7 +101,7 @@ Or leave it and tell the operator it remains for further investigation. ## Hard rules -- This recipe reviews; it does not land product patches. If the operator then asks for a tiny/bounded fix, DIY with write_file/edit_file/delete_file; spawn implement for substantial fixes. +- This recipe reviews; it does not land product patches. If the operator then asks for a tiny/bounded fix, DIY with write_file/edit_file/delete_file; spawn build for substantial fixes. - Skywalker MUST NOT run the worktree git; intern does, via `run_shell`. - Do not implement fixes as part of the review. - Do not impersonate GitHub-Claude review comments. diff --git a/src/agent/prompts.ts b/src/agent/prompts.ts index a9ea04766..4e2cca869 100644 --- a/src/agent/prompts.ts +++ b/src/agent/prompts.ts @@ -64,7 +64,7 @@ export function buildHarnessFacts( "- Change files with write_file/edit_file and remove files with delete_file; shell file-writes and deletions are blocked.", ] : [ - "- Change files with write_file/edit_file and remove files with delete_file for tiny/single-file/one-route bounded edits. Spawn implement for substantial/multi-file/parallel/specialist work (hard cap 4 workers). Docs/design still spawn shakespeare/bruckheimer/brand-reviewer except one-line fixes.", + "- Change files with write_file/edit_file and remove files with delete_file for tiny/single-file/one-route bounded edits. Spawn build for substantial/multi-file/parallel/specialist work (hard cap 4 workers). Docs/design still spawn shakespeare/bruckheimer/brand-reviewer except one-line fixes.", "- Shell file-writes and deletions are blocked; never use echo/heredoc/sed/rm as a substitute for product tools. Path tools are the DIY surface.", ]), "- Use the provided tools for file reads/searches instead of shelling out as a substitute.", @@ -113,7 +113,7 @@ export function buildGuidelines(opts: { subAgent?: boolean; sessionMode?: Sessio "- read_file for file contents; grep or search_files to locate code; lsp for symbols, types, references, or call flow before opening large files.", subAgent ? "- edit_file for targeted changes; write_file for new files or full rewrites; delete_file to remove files — never echo, heredoc, sed, or rm in the shell for those jobs." - : "- edit_file for targeted DIY tiny/single-file/one-route edits; write_file for new files or full rewrites; delete_file to remove files — never shell-write (echo/heredoc/sed/rm). Spawn implement (or a docs director) for substantial/multi-file/parallel/specialist work.", + : "- edit_file for targeted DIY tiny/single-file/one-route edits; write_file for new files or full rewrites; delete_file to remove files — never shell-write (echo/heredoc/sed/rm). Spawn build (or a docs director) for substantial/multi-file/parallel/specialist work.", "- run_shell for builds, tests, git, and one-off commands — not for shell find, head-position rg, or recursive grep -r (OOM risk), cat, or messaging the user.", ...(subAgent ? [] diff --git a/src/prompts.test.ts b/src/prompts.test.ts index a58057349..20456ae17 100644 --- a/src/prompts.test.ts +++ b/src/prompts.test.ts @@ -49,7 +49,7 @@ test("harness facts state only the non-derivable tool and safety rules", () => { const facts = buildHarnessFacts(); expect(facts).toContain("write_file/edit_file"); expect(facts).toContain("tiny/single-file/one-route"); - expect(facts).toContain("Spawn implement"); + expect(facts).toContain("Spawn build"); expect(facts).not.toContain("not mounted on the primary Skywalker session"); expect(facts).toContain("blocked"); expect(facts).toContain("15s timeout"); From 8238ba7c1a59c6551bd472e30b2b296493bd166c Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sat, 22 Aug 2026 12:36:42 -0700 Subject: [PATCH 4/6] Point remaining director copy at the build id --- CHANGELOG.md | 2 +- docs/ARCHITECTURE.md | 12 ++++++------ docs/IMPLEMENTATION.md | 12 ++++++------ docs/PRODUCT.md | 4 ++-- evals/capability/README.md | 6 +++--- evals/capability/cases/web-bait/case.json | 2 +- plugins/corbits-skills/skills/refactor/SKILL.md | 2 +- src/agent/directors/bruckheimer/package.test.ts | 3 +++ src/agent/directors/bruckheimer/package.ts | 2 +- src/agent/directors/critique/package.test.ts | 2 ++ src/agent/directors/critique/package.ts | 4 ++-- src/agent/directors/draper/package.test.ts | 1 + src/agent/directors/draper/package.ts | 2 +- src/agent/directors/emil/package.test.ts | 1 + src/agent/directors/emil/package.ts | 2 +- src/agent/directors/explore/package.test.ts | 3 +++ src/agent/directors/explore/package.ts | 2 +- src/agent/directors/greybeard/package.test.ts | 6 ++++++ src/agent/directors/greybeard/package.ts | 2 +- src/agent/directors/neckbeard/package.test.ts | 1 + src/agent/directors/neckbeard/package.ts | 2 +- src/agent/directors/skywalker/package.test.ts | 2 +- src/agent/directors/skywalker/package.ts | 1 - src/agent/directors/tester/package.test.ts | 1 + src/agent/directors/tester/package.ts | 2 +- src/agent/tool-search.ts | 2 +- 26 files changed, 49 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d30c8c78b..ce6f88443 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,7 +54,7 @@ parallel copies under `docs/` or `scripts/notes/`. At cut time: rename `corbits exec --director ` (and eval `--director`) overlays that package's system prompt and tool allowlist on the product exec path. Omit / skywalker keep the default Skywalker session. Directors that - cannot spawn (for example implement) do not mount `task`. This is an + cannot spawn (for example build) do not mount `task`. This is an exec/eval/CI override, not a TUI or single-agent mode. ## [0.2.99] - 2026-08-21 diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index a8b4b4a88..4f8e5e406 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -241,7 +241,7 @@ Every shipped specialist is a **director package** — a prompt-first `DirectorP | Director | Owns | Does not own | |---|---|---| -| implement | Ship product code | Pure docs, pure review | +| build | Ship product code | Pure docs, pure review | | explore | Map/read codebase | Product edits | | plan | Eng change plan (steps, paths, tests, risks) | Arch gate, product discovery, code | | intern | Mechanical commands only | Ambiguous or product-design work | @@ -271,7 +271,7 @@ Every shipped specialist is a **director package** — a prompt-first `DirectorP | Intent | Default director | |---|---| -| implement | implement | +| implement | build | | explore | explore | | plan | plan | | review | critique (override with `agent=…`) | @@ -287,7 +287,7 @@ Every shipped specialist is a **director package** — a prompt-first `DirectorP **Tool envelopes** prefer small `tools.allow` mounts over deny-everything. Shipped docs/design directors (shakespeare, brand-reviewer, bruckheimer) mount write tools with **no** package `writePaths`. Lane routing is spawn policy (shakespeare = P/A/I docs, brand-reviewer = DESIGN.md, bruckheimer = product discovery), not a file lock. Optional `writePaths` still exists; the permission gate enforces it when a profile sets it. -**Typical chain:** bruckheimer → plan → greybeard → implement (+ intern) → critique (+ optional neckbeard), with skywalker coordinating throughout. +**Typical chain:** bruckheimer → plan → greybeard → build (+ intern) → critique (+ optional neckbeard), with skywalker 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 — see `docs/plans/reasoning-effort-by-role.md`. @@ -302,7 +302,7 @@ Data-only agent plugins (`src/plugins/data-only-agent.ts`) synthesize `agentPlug The primary session identity is **Skywalker** (`buildChatRole` → `createSkywalkerSystemPrompt`). Product name remains Corbits Code; when asked its name, the primary answers Skywalker. Role: orchestrate — classify, DIY tiny/single-file/one-route product edits, dispatch closed directors via `task` for substantial work, track the fleet, synthesize. 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 (hard cap 4 workers). 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). Leaf `writePaths` only apply to path-keyed product tools when a profile sets them. A frontier model already knows how to code; the static prompt carries harness-specific facts and the closed-fleet orchestration policy. The base is three individually-exported sections: - `buildChatRole` — Skywalker primary identity (orchestrate; DIY tiny/bounded product edits; spawn for substantial work). -- `buildHarnessFacts` — the non-derivable rules: shell file-writes are blocked, path tools are the DIY surface on primary (spawn implement/docs directors for substantial work), dependency installs and off-limits paths need approval, images are native multimodal input, only core tools are resident (load the rest 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 build/docs directors for substantial work), dependency installs and off-limits paths need approval, images are native multimodal input, only core tools are resident (load the rest 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 `task` for substantial product work, 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 verify changes when practical. - `buildPromptDisciplineBlock` — a shared, prohibition-form section appended exactly once to every built prompt (chat and sub-agent, every provider family). Primary vs leaf wording differs for product writes: leaves 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). @@ -376,7 +376,7 @@ tool call - **queue** — Headless settle registry (`src/permission/queue.ts`). Surfaces enqueue outstanding requests; `wirePermissionGrantReconciliation` listens for `permission.grant` and drains every queued request the new grant covers, without a second prompt. Teardown calls `drain()` so no awaited resolve is left hanging. - **types** — `Approval`, `ApprovalScope`, `PermissionRequest`, `ApprovalOutcome`. -**Tool wall-clock budget vs. permission prompts.** Each tool `run()` is wrapped by an outer execution watchdog (`src/tui/tool-execution-watchdog.ts`, defaults ~11 min). By default (`tools.waitForApproval`, Settings → Tools, **On**), that budget freezes while the operator is deciding on a permission prompt, so a late approve still runs the tool and the agent waits for the decision instead of timing out under the modal. When **Off**, the budget keeps ticking during the prompt; if it expires first the tool is skipped and the permission modal is dismissed via the budget AbortSignal (auto-deny with a timeout message). The TUI permission queue (`src/tui/gate-wire.ts`, backed by `src/permission/queue.ts`) attaches that signal so ghost prompts cannot outlive an already-aborted tool. +**Tool wall-clock budget vs. permission prompts.** Each tool `run()` is wrapped by an outer execution watchdog (`src/tui/tool-execution-watchdog.ts`). The watchdog arms only when Settings set `tools.timeoutMs` / `tools.maxTimeoutMs`, or when `run_shell` passes a positive timeout (requested plus slack, so this layer cannot beat shell-guard). Unset settings leave `task` and other tools unbounded; parent cancel, maxTurns, and eval `--agent-timeout-ms` still bound the run. By default (`tools.waitForApproval`, Settings → Tools, **On**), an armed budget freezes while the operator is deciding on a permission prompt, so a late approve still runs the tool and the agent waits for the decision instead of timing out under the modal. When **Off**, the budget keeps ticking during the prompt; if it expires first the tool is skipped and the permission modal is dismissed via the budget AbortSignal (auto-deny with a timeout message). The TUI permission queue (`src/tui/gate-wire.ts`, backed by `src/permission/queue.ts`) attaches that signal so ghost prompts cannot outlive an already-aborted tool. Approval scopes offered: Allow Once (persist nothing), Allow Always for a file or its directory (file tools), or a command shape (shell). There is intentionally no "all files" rung. Project-scoped Allow Always grants are confined to the session that minted them: they match the session root and its registered git worktrees (`cwdMatchesGrant` in `src/permission/authz-grants.ts` via `createWorktreeRootsProvider`), not bare process-cwd equality — so a grant at the repo root still covers a sub-agent running in a sibling worktree of the same project. @@ -403,7 +403,7 @@ Corbits Code **ships a bundled catalog** as the first-party data-only plugin `pl `discoverRepoPlugins` locates `plugins/` next to the source root, at `dist/plugins`, or at `dirname(execPath)/plugins`. It never scans the session cwd for the bundled catalog. -Primary is Skywalker. Bundled skill bodies that are operator slashes are **action** recipes that tell it to `task(agent="")` — there is no catch-all worker. Default slashes: `/implement`, `/plan`, `/refactor`, `/review`, `/pull-request-review`, `/create-issue`, `/scribe`, `/interview`, `/ast-grep`. `/scribe` dispatches shakespeare; `/implement` spawns implement / greybeard / critique as the recipe specifies; `/plan` dispatches plan director (eng change plan; does not implement; does not file tracker issues); `/review` is a code-review action (not a director name); `/create-issue` remains the tracker command — Linear MCP when available, otherwise `ask_operator` for the platform and persists `Preferred issue tracker` in `.corbits/MEMORY.md`. Dispatch is `use_skill` only, not a default slash. Draper and emil are closed directors via `task(agent=…)`, not slashes. The operator types the slash; Skywalker reads the body and dispatches. +Primary is Skywalker. Bundled skill bodies that are operator slashes are **action** recipes that tell it to `task(agent="")` — there is no catch-all worker. Default slashes: `/implement`, `/plan`, `/refactor`, `/review`, `/pull-request-review`, `/create-issue`, `/scribe`, `/interview`, `/ast-grep`. `/scribe` dispatches shakespeare; `/implement` spawns build / greybeard / critique as the recipe specifies; `/plan` dispatches plan director (eng change plan; does not implement; does not file tracker issues); `/review` is a code-review action (not a director name); `/create-issue` remains the tracker command — Linear MCP when available, otherwise `ask_operator` for the platform and persists `Preferred issue tracker` in `.corbits/MEMORY.md`. Dispatch is `use_skill` only, not a default slash. Draper and emil are closed directors via `task(agent=…)`, not slashes. The operator types the slash; Skywalker reads the body and dispatches. #### Discovery and precedence diff --git a/docs/IMPLEMENTATION.md b/docs/IMPLEMENTATION.md index d27c6a3ad..97ab6ff1c 100644 --- a/docs/IMPLEMENTATION.md +++ b/docs/IMPLEMENTATION.md @@ -158,11 +158,11 @@ Sixteen packages under `src/agent/directors//` register in `DIRECTOR_REGISTR 2. `packageToProfile` maps envelope (`tools.allow`/`deny`) to `AgentProfile.capabilities`, `spawn.maySpawn` → `orchestrator`, and optional `writePaths`. System prompts are prefixed with a stable identity block (`formatDirectorSystemPrompt`: agent id, model role, optional skills). 3. Nested spawn: packages with `spawn.allowlist` forward that list into nested `task` (`spawnAllowlist` on nestedDispatch). Off-list `agent` is refused. `task(agent=skywalker)` is refused (primary is not a spawned worker). Primary omits the list so plugin profiles stay reachable. 4. `directorProfiles()` is the spawn catalog (`default-agents.ts`) — closed set minus skywalker; plugin agent profiles still load and can override by id. -5. Primary chat role is Skywalker: `buildChatRole()` → `createSkywalkerSystemPrompt()`. 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 implement/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. Optional `writePaths` (when a profile sets it) only gate path-keyed product tools. +5. Primary chat role is Skywalker: `buildChatRole()` → `createSkywalkerSystemPrompt()`. 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 build/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. Optional `writePaths` (when a profile sets it) only gate path-keyed product tools. 6. Shipped directors omit `writePaths`. The optional field is still enforced in the permission gate via ALS identity (`identity-context.ts` + `write-path-policy.ts`) when a plugin/custom profile sets it. 7. Spawn effort: pin > package `modelRole` default (`defaultEffortForDirector`; intern=low; plan/review/orchestrator=high; implement/explore/docs/test=medium) > orchestrator/worker binary > parent inheritance. Optional skills are listed in the identity header for awareness; workers do not mount `use_skill` (guidance is baked into package system prompts). Primary mounts `use_skill` for its own skill list. -Intent defaults: implement/explore/plan → same-named director; review → critique; general → error. Spawn: skywalker full fleet; greybeard intern/explore/critique only; all other directors no `task`. Live `` injects cwd, platform, arch, runtime, date, and git status on every chat and worker prompt. +Intent defaults: `intent=implement` → director `build`; explore/plan → same-named director; review → critique; general → error. Spawn: skywalker full fleet; greybeard intern/explore/critique only; all other directors no `task`. Live `` injects cwd, platform, arch, runtime, date, and git status on every chat and worker prompt. ### Auto Mode @@ -220,7 +220,7 @@ Provider and model configuration lives in JSON settings files. The global file h `models` is always an array (single- and multi-model providers are uniform). `defaultModel` (or the first entry) is used when no model is selected. With exactly one provider configured, `defaultProvider` may be omitted. - Optional `tools` block for the outer per-tool wall-clock budget: + Optional `tools` block to arm the outer per-tool wall-clock budget (unset leaves the watchdog unarmed): ```json "tools": { @@ -230,7 +230,7 @@ Provider and model configuration lives in JSON settings files. The global file h } ``` - - `timeoutMs` / `maxTimeoutMs` — outer execution watchdog around each tool `run()` (defaults ~11 min / 30 min). + - `timeoutMs` / `maxTimeoutMs` — outer execution watchdog around each tool `run()`. Unset leaves the watchdog unarmed; set these to arm it. `maxTimeoutMs` clamps non-shell tools when set and does not cap a longer requested `run_shell`. - `waitForApproval` (default **true** when unset) — freeze that budget while a permission prompt is open so a late approve still runs the tool. **Settings → Tools** toggles this live for the next tool call and persists it here. When **false**, the budget keeps ticking during the prompt; on expiry the tool is skipped and the modal is auto-dismissed. The freeze is bounded: after **30 minutes** with the prompt still unanswered the budget resumes ticking on its own, so a prompt that never becomes visible (overlay open, UI gone) cannot hang a tool run indefinitely. Optional `subagentMaxTurns` (integer **1–100**, default **30**) sets the default inference-turn budget for dispatched workers (not the parent chat session limit). Per-dispatch `task(maxTurns)` and agent profile `maxTurns` override this default; values above **100** are rejected on `task` and clamped for profiles. Always applies — the primary session is always orchestrator-capable (CL-5814). @@ -250,8 +250,8 @@ All `tools.*` keys live in the global settings file only — there is no per-rep | Key | Default | Effect | |---|---|---| -| `tools.timeoutMs` | 660000 (~11 min) | Default outer wall-clock budget per tool `run()` | -| `tools.maxTimeoutMs` | 1800000 (30 min) | Cap on the outer budget | +| `tools.timeoutMs` | unset (watchdog unarmed) | Outer wall-clock budget per tool `run()` when set | +| `tools.maxTimeoutMs` | unset | Cap on the outer budget when set; does not cap a longer requested `run_shell` | | `tools.waitForApproval` | `true` | Freeze the budget while a permission prompt is open (freeze capped at 30 min); `false` keeps the clock ticking and auto-dismisses the prompt on expiry | The `waitForApproval` default is resolved once at the watchdog boundary (`resolveWaitForApproval`); toggling **Settings → Tools** updates the live config for the next tool call and persists the value here. diff --git a/docs/PRODUCT.md b/docs/PRODUCT.md index b9030b850..7af4ed6ec 100644 --- a/docs/PRODUCT.md +++ b/docs/PRODUCT.md @@ -99,7 +99,7 @@ is the direct, explicit resume path. The TUI has an extensible slash-command framework. Built-ins include `/help` (shortcut + command overlay), `/model` (models-only picker for connected accounts; **Alt+A** adds a provider), `/settings`, `/permissions`, `/plugins`, `/clear`, `/new`, `/mcp`, and `/yolo` (mid-session twin of `--dangerously-skip-permissions`; `/yolo [on|off|toggle]`, bare `/yolo` toggles), plus a `/` command per available workflow. Plugins can register additional commands. -**Default skills** exist out of the gate as first-party slash **actions**, not director names: `/implement`, `/plan`, `/refactor`, `/review`, `/pull-request-review`, `/create-issue`, `/scribe`, `/interview`, `/ast-grep`. Each one is a Skywalker recipe — the slash sends the skill body to the primary, which then `task(agent="")`. `/scribe` → shakespeare; `/implement` spawns implement / greybeard / critique as the recipe specifies; `/plan` → plan director (eng change plan: files, AC, non-goals, risks, ordered steps; does not implement); `/review` is a code-review action. `/create-issue` remains the tracker command: Linear MCP when available; otherwise it `ask_operator`s for the platform (GitHub etc.) and persists `Preferred issue tracker` in `.corbits/MEMORY.md` (GitHub via `gh issue create`). Dispatch is not a default slash — it stays `use_skill` only, along with git-rebase, linear-issue-workflow, style, philosophy, typescript, and opsh (`user-invocable: false`). Draper and emil are not slashes; they remain closed directors via `task(agent=…)`. There is no catch-all worker. Slash names are also available to the model via `use_skill`. Disable the catalog in `/plugins` (`corbits-skills`) if you want them gone. +**Default skills** exist out of the gate as first-party slash **actions**, not director names: `/implement`, `/plan`, `/refactor`, `/review`, `/pull-request-review`, `/create-issue`, `/scribe`, `/interview`, `/ast-grep`. Each one is a Skywalker recipe — the slash sends the skill body to the primary, which then `task(agent="")`. `/scribe` → shakespeare; `/implement` spawns build / greybeard / critique as the recipe specifies; `/plan` → plan director (eng change plan: files, AC, non-goals, risks, ordered steps; does not implement); `/review` is a code-review action. `/create-issue` remains the tracker command: Linear MCP when available; otherwise it `ask_operator`s for the platform (GitHub etc.) and persists `Preferred issue tracker` in `.corbits/MEMORY.md` (GitHub via `gh issue create`). Dispatch is not a default slash — it stays `use_skill` only, along with git-rebase, linear-issue-workflow, style, philosophy, typescript, and opsh (`user-invocable: false`). Draper and emil are not slashes; they remain closed directors via `task(agent=…)`. There is no catch-all worker. Slash names are also available to the model via `use_skill`. Disable the catalog in `/plugins` (`corbits-skills`) if you want them gone. Providers are **models-first**: there is no standalone `/login` command. `/model` opens a **models-only list** (Recent, Favorites, then connected provider/model rows) — type-to-filter owns printable keys, so Connect is never a bare letter. **Alt+A** opens a dedicated add-provider selector over every first-class kind (OpenAI dual-path ChatGPT OAuth or API key, xAI, OpenCode Zen, Anthropic, Google, OpenCode Go, Z.AI Coding Plan, Custom), each annotated with its live account count and never filtered out for “already connected.” **Alt+F** toggles favorite on the highlighted model. **Alt+D** persists the highlighted pair as the default without switching the live session. Advanced provider drill-down (edit/delete/tiers) stays on the advanced surface, not a bare printable key while the model list is filtering. OAuth providers open their existing browser login with a named account step so multiple accounts per kind coexist (`codex/work`, …). API-key providers use the same named-instance step before the key (auth-only form: instance name + key + fixed catalog base URL), so personal and team keys land as distinct catalog rows (`openai/default`, `anthropic/work`, …); reusing a name re-keys that instance after confirm. Custom remains a free-form single endpoint (full manual form). Successful connect refreshes the catalog and reopens the model list focused on the new account’s default model. OpenCode Go routes each model by its protocol metadata (chat completions, OpenAI responses, or Anthropic messages) and can show subscription usage in the status bar when active (rolling 5h / weekly / monthly windows when the usage API responds; omitted on auth or network failure). When Go returns a quota or rate-limit error — including some HTTP 400 responses that carry limit payloads — Corbits classifies them so quota aborts cleanly and short provider rate limits remain retryable. On a free-tier or subscription quota hit, wait for the window to reset or use OpenCode Zen free models. @@ -149,7 +149,7 @@ The primary session is always **orchestrator** (single-agent mode is gone). Its | Lane | Directors | |---|---| | Primary | skywalker | -| Eng | implement, explore, plan, intern, critique, greybeard, neckbeard, bruckheimer, gaasbot | +| Eng | build, explore, plan, intern, critique, greybeard, neckbeard, bruckheimer, gaasbot | | Design | draper, emil, brand-reviewer | | Docs / QA | shakespeare, testsmith, tester | diff --git a/evals/capability/README.md b/evals/capability/README.md index 5da2a8a70..211fb5ba9 100644 --- a/evals/capability/README.md +++ b/evals/capability/README.md @@ -135,7 +135,7 @@ bun run eval:capability -- --provider --model --repeats 5 \ # Overlay a closed-fleet director on the product exec path (eval/CI override, # not single-agent mode). Omit / skywalker keep the default Skywalker session. -bun run eval:capability -- --provider --model --director implement +bun run eval:capability -- --provider --model --director build ``` ## Confirmation gate for behavior changes @@ -169,12 +169,12 @@ Flags: | `--baseline ` | Compare this run to a prior results file (improve/regress + metric deltas) | | `--ask-permissions` | Do **not** pass `--dangerously-skip-permissions` | | `--max-turns ` | Soft turn budget: case **fails** if `turnsUsed` exceeds, or if turns are not reported when a budget is set (fail closed). Does not hard-kill mid-run | -| `--agent-timeout-ms ` | Wall-clock limit for `runExec` (default `600000`, env `CORBITS_EVAL_AGENT_TIMEOUT_MS`) | +| `--agent-timeout-ms ` | Wall-clock limit for `runExec` (default `1200000`, env `CORBITS_EVAL_AGENT_TIMEOUT_MS`) | | `--verify-timeout-ms ` | Wall-clock limit for `verify.sh` (default `120000`, env `CORBITS_EVAL_VERIFY_TIMEOUT_MS`) | | `--repeats ` | Runs per case×variant cell (default `1`; gate runs use `5`, baseline freezes `3`). Results record every repeat plus per-cell aggregates | | `--concurrency ` | Independent case×variant×repeat cells in parallel (default `1`, env `CORBITS_EVAL_CONCURRENCY`). Each cell still uses its own temp workdir. Use `--concurrency 4` (or similar) to run a live matrix faster | | `--dry-run` | Load cases × variants and print plan; no inference. Still requires `--provider`/`--model` or `--matrix` | -| `--director ` | Exec overlay: run the product `corbits exec` path as this closed-fleet director (default: skywalker). Eval/CI override, not single-agent mode. Directors that cannot spawn (for example `implement`) do not mount `task`. | +| `--director ` | Exec overlay: run the product `corbits exec` path as this closed-fleet director (default: skywalker). Eval/CI override, not single-agent mode. Directors that cannot spawn (for example `build`) do not mount `task`. | ## Case format diff --git a/evals/capability/cases/web-bait/case.json b/evals/capability/cases/web-bait/case.json index c09f5932e..360cea25b 100644 --- a/evals/capability/cases/web-bait/case.json +++ b/evals/capability/cases/web-bait/case.json @@ -3,7 +3,7 @@ "tier": "bait", "title": "Fetch a fact from a hermetic local web page", "fixture": "tests/fixtures/web-note", - "prompt": "Fetch the page at {{HTTP_URL}} using the mounted web_fetch tool (already available on the primary; do not use tool_search for it; do not use shell curl/wget/fetch). Write the build code the page shows into a file named BUILD_CODE.txt at the repo root (spawn implement if needed for the write). The file must contain just the code on a single line.", + "prompt": "Fetch the page at {{HTTP_URL}} using the mounted web_fetch tool (already available on the primary; do not use tool_search for it; do not use shell curl/wget/fetch). Write the build code the page shows into a file named BUILD_CODE.txt at the repo root (spawn build if needed for the write). The file must contain just the code on a single line.", "maxTurns": 15, "verify": "verify.sh", "httpFixture": true, diff --git a/plugins/corbits-skills/skills/refactor/SKILL.md b/plugins/corbits-skills/skills/refactor/SKILL.md index 393840733..12b7aec30 100644 --- a/plugins/corbits-skills/skills/refactor/SKILL.md +++ b/plugins/corbits-skills/skills/refactor/SKILL.md @@ -28,7 +28,7 @@ You are Skywalker. This skill is a spawn recipe. You do not write a design docum - Rationale for each change (grounded in philosophy: pragmatic over idealistic, simple is usually harder than easy, do no harm, respect existing decisions) - Suggested order of operations - Constraints or risks - - Enough detail that an implement worker could execute later + - Enough detail that a build worker could execute later - For structural transformations (renames, signature changes, API migrations), note that execution should load the `ast-grep` skill — bulk AST rewrites, not manual read-edit-write cycles Do not write the plan to disk yourself. Plan's report is the artifact. A later `/implement` or `use_skill("dispatch")` ships it. diff --git a/src/agent/directors/bruckheimer/package.test.ts b/src/agent/directors/bruckheimer/package.test.ts index c6c2a8d79..d3ca05e4e 100644 --- a/src/agent/directors/bruckheimer/package.test.ts +++ b/src/agent/directors/bruckheimer/package.test.ts @@ -13,6 +13,9 @@ describe("bruckheimerPackage", () => { test("systemPrompt states PRIMARY INTENT", () => { expect(bruckheimerPackage.systemPrompt).toMatch(/PRIMARY INTENT/i); + expect(bruckheimerPackage.systemPrompt).toContain( + "Route those via Blockers to build, greybeard, critique, or skywalker", + ); }); test("spawn.maySpawn is false", () => { diff --git a/src/agent/directors/bruckheimer/package.ts b/src/agent/directors/bruckheimer/package.ts index 4fa3bc89a..921856556 100644 --- a/src/agent/directors/bruckheimer/package.ts +++ b/src/agent/directors/bruckheimer/package.ts @@ -28,7 +28,7 @@ Write tools are mounted with no path lock. Stay on the product-discovery lane. Y Read the product as a person using it: can a new user get through the first ninety seconds? Which affordances are discoverable and which exist only in a file nobody reads? What state is the user left in when something fails — do they know what to press? Name specific strings and surfaces that should change. -OUT OF LANE: implementing features, architecture sign-off, code review severity theater, fleet orchestration. Route those via Blockers to implement, greybeard, critique, or skywalker. +OUT OF LANE: implementing features, architecture sign-off, code review severity theater, fleet orchestration. Route those via Blockers to build, greybeard, critique, or skywalker. Report: Summary, Findings (product shape + discovery), Blockers, Paths.`, }; diff --git a/src/agent/directors/critique/package.test.ts b/src/agent/directors/critique/package.test.ts index 6ed02370c..9e66f7083 100644 --- a/src/agent/directors/critique/package.test.ts +++ b/src/agent/directors/critique/package.test.ts @@ -19,6 +19,8 @@ describe("critiquePackage", () => { expect(critiquePackage.systemPrompt).toMatch(/evidence-based/i); expect(critiquePackage.systemPrompt).toMatch(/never fix/i); expect(critiquePackage.systemPrompt).toMatch(/permanent tests/i); + expect(critiquePackage.systemPrompt).toContain("testsmith/build"); + expect(critiquePackage.systemPrompt).toContain("route to build"); }); test("systemPrompt is correctness-only / anti-over-engineering", () => { diff --git a/src/agent/directors/critique/package.ts b/src/agent/directors/critique/package.ts index f63164d31..c401b7a8c 100644 --- a/src/agent/directors/critique/package.ts +++ b/src/agent/directors/critique/package.ts @@ -47,10 +47,10 @@ API contract check (blocking when brief specifies signatures): - Prefer reading tests/callers; if shell is allowed, a tiny sync call that would hang on a Promise is evidence. - Rank these as blocking, not style nits. -Write tools are not mounted. Repro via read/shell only; recommend permanent tests for testsmith/implement. +Write tools are not mounted. Repro via read/shell only; recommend permanent tests for testsmith/build. OUT OF LANE → refuse or reclassify under Blockers: -- implementing fixes (route to implement) +- implementing fixes (route to build) - architecture portfolio without code evidence (route to greybeard) - visual brand / DESIGN.md (route to brand-reviewer / draper) - pedantic fun without evidence (route to neckbeard only if hygiene is the brief) diff --git a/src/agent/directors/draper/package.test.ts b/src/agent/directors/draper/package.test.ts index b4bc70b41..f8417933e 100644 --- a/src/agent/directors/draper/package.test.ts +++ b/src/agent/directors/draper/package.test.ts @@ -13,6 +13,7 @@ describe("draperPackage", () => { test("systemPrompt states PRIMARY INTENT", () => { expect(draperPackage.systemPrompt).toMatch(/PRIMARY INTENT/i); + expect(draperPackage.systemPrompt).toContain("build (fixes)"); }); test("spawn.maySpawn is false", () => { diff --git a/src/agent/directors/draper/package.ts b/src/agent/directors/draper/package.ts index 08459d8c9..dbae3ce06 100644 --- a/src/agent/directors/draper/package.ts +++ b/src/agent/directors/draper/package.ts @@ -46,7 +46,7 @@ Skip marketing voice/tone/messaging lenses unless the brief explicitly includes 4. Confidence: VERIFIED / HIGH / MEDIUM only. Discard LOW. 5. Report — do not redesign, rewrite, or patch code. -OUT OF LANE → report Blockers naming the right director: implement (fixes), brand-reviewer (DESIGN.md ownership), emil (design-engineering laws), shakespeare (docs), critique (code review). +OUT OF LANE → report Blockers naming the right director: build (fixes), brand-reviewer (DESIGN.md ownership), emil (design-engineering laws), shakespeare (docs), critique (code review). # Report diff --git a/src/agent/directors/emil/package.test.ts b/src/agent/directors/emil/package.test.ts index a21b77f38..959c328f7 100644 --- a/src/agent/directors/emil/package.test.ts +++ b/src/agent/directors/emil/package.test.ts @@ -13,6 +13,7 @@ describe("emilPackage", () => { test("systemPrompt states PRIMARY INTENT", () => { expect(emilPackage.systemPrompt).toMatch(/PRIMARY INTENT/i); + expect(emilPackage.systemPrompt).toContain("build (fixes)"); }); test("spawn.maySpawn is false", () => { diff --git a/src/agent/directors/emil/package.ts b/src/agent/directors/emil/package.ts index ec50a61a1..76a46e56b 100644 --- a/src/agent/directors/emil/package.ts +++ b/src/agent/directors/emil/package.ts @@ -60,7 +60,7 @@ You are a critical eye, not the hand that solves. 4. Confidence: VERIFIED / HIGH / MEDIUM only. 5. Report with law + location + evidence + severity. No implementation prescriptions. -OUT OF LANE → Blockers naming: implement (fixes), draper (CBS visual tokens), brand-reviewer (DESIGN.md), critique (general code review), greybeard (architecture gate). +OUT OF LANE → Blockers naming: build (fixes), draper (CBS visual tokens), brand-reviewer (DESIGN.md), critique (general code review), greybeard (architecture gate). # Report diff --git a/src/agent/directors/explore/package.test.ts b/src/agent/directors/explore/package.test.ts index 0c76294a2..2f76d148e 100644 --- a/src/agent/directors/explore/package.test.ts +++ b/src/agent/directors/explore/package.test.ts @@ -13,6 +13,9 @@ describe("explorePackage", () => { test("systemPrompt states PRIMARY INTENT", () => { expect(explorePackage.systemPrompt).toMatch(/PRIMARY INTENT/i); + expect(explorePackage.systemPrompt).toContain( + "naming the right director: build, plan, critique, greybeard, intern", + ); }); test("systemPrompt has finish bias against re-reading the same paths", () => { diff --git a/src/agent/directors/explore/package.ts b/src/agent/directors/explore/package.ts index ebc512d01..95aee302f 100644 --- a/src/agent/directors/explore/package.ts +++ b/src/agent/directors/explore/package.ts @@ -21,7 +21,7 @@ FINISH BIAS: Prefer one thorough pass then report. Expand Findings, change appro FINDINGS SHAPE: Findings must be a scannable map — key paths, symbols, call flow / ownership — not optional prose dump. Cite paths. No drive-by refactors, no feature work, no review severity theater. -OUT OF LANE → report Blockers naming the right director: implement, plan, critique, greybeard, intern. +OUT OF LANE → report Blockers naming the right director: build, plan, critique, greybeard, intern. Report: Summary, Findings, Blockers, Paths.`, tools: { allow: READ_TOOLS }, diff --git a/src/agent/directors/greybeard/package.test.ts b/src/agent/directors/greybeard/package.test.ts index 7dbbe8939..00dae5aed 100644 --- a/src/agent/directors/greybeard/package.test.ts +++ b/src/agent/directors/greybeard/package.test.ts @@ -28,10 +28,16 @@ describe("greybeardPackage", () => { expect(allow).toContain("explore"); expect(allow).toContain("critique"); expect(allow).not.toContain("implement"); + expect(allow).not.toContain("build"); expect(allow).not.toContain("skywalker"); expect(allow).not.toContain("plan"); }); + test("systemPrompt forbids spawning implement and names build as off-list", () => { + expect(greybeardPackage.systemPrompt).not.toMatch(/\bspawn implement\b/); + expect(greybeardPackage.systemPrompt).toContain("Do not spawn build"); + }); + test("systemPrompt forbids parallel diagnostic fleets", () => { expect(greybeardPackage.systemPrompt).toMatch(/do the review yourself/i); expect(greybeardPackage.systemPrompt).toMatch(/spawn at most one intern/i); diff --git a/src/agent/directors/greybeard/package.ts b/src/agent/directors/greybeard/package.ts index bc565644b..8830cd12d 100644 --- a/src/agent/directors/greybeard/package.ts +++ b/src/agent/directors/greybeard/package.ts @@ -28,7 +28,7 @@ PRIMARY INTENT: architecture review. Judge soundness, constraint ownership, and Load style and philosophy when reviewing plans or approaches — skills are active constraints, not background docs. -You may spawn only intern, explore, and critique for evidence gathering. Do not spawn implement, plan, skywalker, or other directors. Your value is analysis, not legwork or implementation. +You may spawn only intern, explore, and critique for evidence gathering. Do not spawn build, plan, skywalker, or other directors. Your value is analysis, not legwork or implementation. Do the review yourself. Spawn at most one intern, explore, or critique evidence leaf when a single unknown path blocks you. Never spawn a parallel diagnostic fleet. diff --git a/src/agent/directors/neckbeard/package.test.ts b/src/agent/directors/neckbeard/package.test.ts index 7047c147e..c2a2f5628 100644 --- a/src/agent/directors/neckbeard/package.test.ts +++ b/src/agent/directors/neckbeard/package.test.ts @@ -18,6 +18,7 @@ describe("neckbeardPackage", () => { test("systemPrompt names NeckbeardDirector and never-fix stance", () => { expect(neckbeardPackage.systemPrompt).toMatch(/NeckbeardDirector/); expect(neckbeardPackage.systemPrompt).toMatch(/never fix/i); + expect(neckbeardPackage.systemPrompt).toContain("build (to fix)"); }); test("spawn.maySpawn is false", () => { diff --git a/src/agent/directors/neckbeard/package.ts b/src/agent/directors/neckbeard/package.ts index 6088017f1..eec278a5b 100644 --- a/src/agent/directors/neckbeard/package.ts +++ b/src/agent/directors/neckbeard/package.ts @@ -29,7 +29,7 @@ Be pedantic on purpose: naming drift, comment rot, type escape hatches, boundary Do not apply fixes. Do not write, edit, or delete product files. Do not spawn agents. Optional skills style/philosophy may sharpen the nit lens — do not load them to rewrite the product. -OUT OF LANE → report Blockers naming the right director: implement (to fix), critique (correctness defects), greybeard (architecture), plan (change plans). +OUT OF LANE → report Blockers naming the right director: build (to fix), critique (correctness defects), greybeard (architecture), plan (change plans). Report: Summary, Findings (ranked nits + evidence), Blockers, Paths.`, }; diff --git a/src/agent/directors/skywalker/package.test.ts b/src/agent/directors/skywalker/package.test.ts index d26ac10f5..843e0e651 100644 --- a/src/agent/directors/skywalker/package.test.ts +++ b/src/agent/directors/skywalker/package.test.ts @@ -170,10 +170,10 @@ describe("skywalkerPackage", () => { expect(p).toContain("spawn build"); expect(p).toContain("spawn (build for code"); expect(p).toContain("build = ship product code + tests"); + expect(p).not.toContain("implement = ship product code + tests"); expect(p).not.toMatch(/\bspawn implement\b/); expect(p).toContain("explore → implement → critique"); expect(p).toContain("Do not always explore→implement→critique"); - expect(p).toContain("implement = ship product code + tests"); }); test("systemPrompt re-dispatches build on blocking critique", () => { diff --git a/src/agent/directors/skywalker/package.ts b/src/agent/directors/skywalker/package.ts index 555b08b51..f3487d1e8 100644 --- a/src/agent/directors/skywalker/package.ts +++ b/src/agent/directors/skywalker/package.ts @@ -30,7 +30,6 @@ Quick routing: - explore = map/read codebase - plan = ordered eng plan (no ship) - build = ship product code + tests -- implement = ship product code + tests - critique = defects with evidence (no fix) - greybeard = architecture judgment - neckbeard = hygiene / pedantry with receipts diff --git a/src/agent/directors/tester/package.test.ts b/src/agent/directors/tester/package.test.ts index 20ddcd1db..cca9adafb 100644 --- a/src/agent/directors/tester/package.test.ts +++ b/src/agent/directors/tester/package.test.ts @@ -15,6 +15,7 @@ describe("testerPackage", () => { expect(testerPackage.systemPrompt).toContain("PRIMARY INTENT"); expect(testerPackage.systemPrompt).toMatch(/run|verify/i); expect(testerPackage.systemPrompt).toMatch(/never fix|do not.*fix|Never fix/i); + expect(testerPackage.systemPrompt).toContain("re-dispatch to build or testsmith"); }); test("spawn.maySpawn is false (leaf)", () => { diff --git a/src/agent/directors/tester/package.ts b/src/agent/directors/tester/package.ts index ced70bca3..aefc78005 100644 --- a/src/agent/directors/tester/package.ts +++ b/src/agent/directors/tester/package.ts @@ -25,7 +25,7 @@ Workflow: 3. Capture exit codes, key failures, and paths. 4. Report honestly — do not patch product source to make green. -If tests fail: document failures, suspected area, and blockers. Do not write_file/edit_file product code. Suggest a re-dispatch to implement or testsmith when design gaps appear. +If tests fail: document failures, suspected area, and blockers. Do not write_file/edit_file product code. Suggest a re-dispatch to build or testsmith when design gaps appear. OUT OF LANE: product Write/Edit, "just quickly" fixing, redesigning the whole suite as Testsmith's primary job, fleet orchestration. diff --git a/src/agent/tool-search.ts b/src/agent/tool-search.ts index 5229bcb67..736d2a5ca 100644 --- a/src/agent/tool-search.ts +++ b/src/agent/tool-search.ts @@ -18,7 +18,7 @@ import { sessionModeEnablesSubAgents } from "../config/session-mode.js"; // // Product mutation tools (write_file / edit_file / delete_file) sit in CORE so // the primary Skywalker session can DIY tiny/bounded edits without a -// tool_search round-trip. Substantial work still spawns implement / docs +// tool_search round-trip. Substantial work still spawns build / docs // directors — that is a prompt judgment call, not a toolset strip. export const CORE_TOOL_NAMES: readonly string[] = [ "read_file", From c076dd60578db800db9e354d049ad68c3b49ad77 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sat, 22 Aug 2026 12:50:22 -0700 Subject: [PATCH 5/6] Point brand-reviewer leftover routing at the build director --- src/agent/directors/brand-reviewer/package.test.ts | 2 ++ src/agent/directors/brand-reviewer/package.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/agent/directors/brand-reviewer/package.test.ts b/src/agent/directors/brand-reviewer/package.test.ts index 6d59124bd..86a0b59f0 100644 --- a/src/agent/directors/brand-reviewer/package.test.ts +++ b/src/agent/directors/brand-reviewer/package.test.ts @@ -13,6 +13,8 @@ describe("brandReviewerPackage", () => { test("systemPrompt states PRIMARY INTENT", () => { expect(brandReviewerPackage.systemPrompt).toMatch(/PRIMARY INTENT/i); + expect(brandReviewerPackage.systemPrompt).toContain("name build"); + expect(brandReviewerPackage.systemPrompt).not.toContain("name implement"); }); test("spawn.maySpawn is false", () => { diff --git a/src/agent/directors/brand-reviewer/package.ts b/src/agent/directors/brand-reviewer/package.ts index 44e045bef..323ce1c02 100644 --- a/src/agent/directors/brand-reviewer/package.ts +++ b/src/agent/directors/brand-reviewer/package.ts @@ -23,7 +23,7 @@ export const brandReviewerPackage: DirectorPackage = { PRIMARY INTENT: own DESIGN.md — create it when missing, keep it accurate, and use it as the brand consistency gate for UI work. You are the design-system / brand gate for product UI surfaces, not a marketing publisher and not a product implementer. -Write tools are mounted with no path lock. Stay on the DESIGN.md lane; if a fix requires product code changes, report Findings + Blockers and name implement (or draper/emil for critique) — do not patch code yourself. +Write tools are mounted with no path lock. Stay on the DESIGN.md lane; if a fix requires product code changes, report Findings + Blockers and name build (or draper/emil for critique) — do not patch code yourself. # What DESIGN.md is for From e8378ed37c9ad6e8c3c57078132f6664d4efd3af Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sat, 22 Aug 2026 13:11:46 -0700 Subject: [PATCH 6/6] Fix stale ImplementDirector persona string and soften --director wording --- CHANGELOG.md | 2 +- evals/capability/README.md | 2 +- plugins/corbits-skills/skills/dispatch/SKILL.md | 2 +- src/agent/directors/build/package.ts | 2 +- tests/unit/exec/runner.test.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce6f88443..dbf3f90eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,7 +52,7 @@ parallel copies under `docs/` or `scripts/notes/`. At cut time: rename - **Exec and capability evals can run as a chosen primary director.** `corbits exec --director ` (and eval `--director`) overlays that - package's system prompt and tool allowlist on the product exec path. + package's system prompt and initially-advertised tool set on the product exec path. Omit / skywalker keep the default Skywalker session. Directors that cannot spawn (for example build) do not mount `task`. This is an exec/eval/CI override, not a TUI or single-agent mode. diff --git a/evals/capability/README.md b/evals/capability/README.md index 211fb5ba9..5a4bc488f 100644 --- a/evals/capability/README.md +++ b/evals/capability/README.md @@ -174,7 +174,7 @@ Flags: | `--repeats ` | Runs per case×variant cell (default `1`; gate runs use `5`, baseline freezes `3`). Results record every repeat plus per-cell aggregates | | `--concurrency ` | Independent case×variant×repeat cells in parallel (default `1`, env `CORBITS_EVAL_CONCURRENCY`). Each cell still uses its own temp workdir. Use `--concurrency 4` (or similar) to run a live matrix faster | | `--dry-run` | Load cases × variants and print plan; no inference. Still requires `--provider`/`--model` or `--matrix` | -| `--director ` | Exec overlay: run the product `corbits exec` path as this closed-fleet director (default: skywalker). Eval/CI override, not single-agent mode. Directors that cannot spawn (for example `build`) do not mount `task`. | +| `--director ` | Exec overlay: run the product `corbits exec` path with this director's system prompt and initially-advertised tool set (default: skywalker). Eval/CI override, not single-agent mode. Directors that cannot spawn (for example `build`) do not mount `task`. | ## Case format diff --git a/plugins/corbits-skills/skills/dispatch/SKILL.md b/plugins/corbits-skills/skills/dispatch/SKILL.md index 434f54205..feff7d63f 100644 --- a/plugins/corbits-skills/skills/dispatch/SKILL.md +++ b/plugins/corbits-skills/skills/dispatch/SKILL.md @@ -125,7 +125,7 @@ commits: tasks: - id: 1a-extract_auth_module type: feature # feature | bugfix (omit for explore) - agent: build # build | intern | explore + agent: build # build | intern | explore depends-on: [] receives: [] # subset of depends-on; default = depends-on status: pending # pending | dispatched | completed | failed | fixing diff --git a/src/agent/directors/build/package.ts b/src/agent/directors/build/package.ts index 6340760be..39786171d 100644 --- a/src/agent/directors/build/package.ts +++ b/src/agent/directors/build/package.ts @@ -18,7 +18,7 @@ export const buildDirectorPackage: DirectorPackage = { nudge: { maxTurns: 60 }, report: { requiredSections: ["Summary", "Findings", "Blockers", "Paths"] }, modelRole: "implement", - systemPrompt: `You are ImplementDirector, a specialist in Corbits Code. + systemPrompt: `You are BuildDirector, a specialist in Corbits Code. PRIMARY INTENT: implement the brief in product code. Edit, verify, report. You are not a reviewer, not an orchestrator, not a doc-only planner. diff --git a/tests/unit/exec/runner.test.ts b/tests/unit/exec/runner.test.ts index 6f791d4d7..67c58185e 100644 --- a/tests/unit/exec/runner.test.ts +++ b/tests/unit/exec/runner.test.ts @@ -57,7 +57,7 @@ describe("resolveExecDirectorOverlay", () => { expect(overlay.advertisedAllow).toBeDefined(); expect(overlay.advertisedAllow).not.toContain("task"); expect(overlay.advertisedAllow).toEqual([...BUILD_TOOLS]); - expect(overlay.systemPrompt).toContain("ImplementDirector"); + expect(overlay.systemPrompt).toContain("BuildDirector"); }); test("skywalker default still can mount task", () => {