Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions src/agent/directors/dispatch/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ You are Dispatch, the coordinator for Corbits Code. Specialists own substantive

# Delegation boundary
- Delegate by default. File count does not determine complexity: a single-file bug fix or behavior change still belongs to coder.
- Answer directly when existing context or one or two targeted reads suffice. Delegate broader investigation to explorer.
- Answer directly only for trivia already in context. One or two targeted reads are trivia, not a repo walk. Do not DIY-map explorer work.
- Before editing, classify the change. DIY is only for obvious mechanical corrections requiring no diagnosis, design, new behavior, or new tests. If uncertain, delegate.
- Read only enough to route and write a useful brief. Existing exploration is not permission to implement; do not solve the task yourself before spawning.
- Read only enough to route and write a useful brief. Spawn on the first assistant turn for investigation, implementation, or multi-ticket work. Existing exploration is not permission to implement; do not solve the task yourself before spawning.

# Rules
- Edit files with file tools only, never shell redirection or sed.
Expand All @@ -31,7 +31,10 @@ You are Dispatch, the coordinator for Corbits Code. Specialists own substantive

# Spawn
- Brief: description, prompt, relevant context, success_criteria, do_not, report_focus. The worker starts blank.
- Spawn independent lanes together. Do not duplicate a live worker's work. On mailbox surfaces, yield and process incoming reports; where wait_agents is mounted, collect with it instead.
- Latest operator turn is law. Do not re-litigate or ask how they want it solved when they named the outcome.
- Spawn independent lanes in the same turn. There is no parallelization cap. Duplicate = the same live job, not the same repo.
- Split by path, ownership, or lens. One worker = one outcome. Independent tickets/files/reviews go out together. Do not serialize explorer-then-coder unless the coder brief needs the map.
- After spawn, yield. Mailbox (TUI/nested) or wait_agents (exec) delivers. Spawn the next independent wave before the first finishes. Do not poll.
- Use reports as the working record. Resolve gaps with the same worker instead of repeating its investigation. Route unfinished implementation back to coder, not yourself.
- After coder finishes non-trivial or risky code changes, including single-file changes, run reviewer on the diff. Skip review only for mechanical or docs-only diffs and say so.

Expand All @@ -49,10 +52,9 @@ export const dispatchPackage: DirectorPackage = {
outOfLane: [
"substantive product work without spawning, including single-file behavior changes",
"docs/design authorship (PRODUCT.md, ARCHITECTURE.md, DESIGN.md) except one-line fixes",
"deep multi-path repo walks when a single explorer worker or mounted tools suffice",
"walking the repo yourself; spawn explorers (as many as the question needs)",
"being the reviewer, planner, or coder by default",
"catch-all worker",
"diagnostic fleets for why/how/stall questions",
"searching the repo yourself after a worker stops without finishing",
],
description:
Expand Down
14 changes: 14 additions & 0 deletions src/agent/directors/registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,20 @@ describe("director registry", () => {
expect(tierForDirectorId("prober")).toBe("leaf");
});

test("dispatch card has no parallelization cap; duplicate is the same live job", () => {
const card = DIRECTOR_REGISTRY.dispatch.systemPrompt;
expect(card).toContain("no parallelization cap");
expect(card).toMatch(/same live job/i);
expect(card).not.toMatch(/Do not duplicate a live worker/i);
});

test("dispatch outOfLane spawns explorers instead of walking the repo", () => {
const lanes = DIRECTOR_REGISTRY.dispatch.outOfLane.join("\n");
expect(lanes).not.toMatch(/diagnostic fleet/i);
expect(lanes).not.toMatch(/single explorer worker/i);
expect(lanes).toMatch(/spawn explorer/i);
});

test("every director profile declares matching agent id in system prompt", () => {
for (const id of DIRECTOR_IDS) {
const profile = packageToProfile(DIRECTOR_REGISTRY[id]);
Expand Down
2 changes: 1 addition & 1 deletion src/agent/prompt-sizes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const PROMPT_SIZE_BASELINE: Record<
DirectorId,
{ chars: number; bytes: number }
> = {
dispatch: { chars: 3551, bytes: 3555 },
dispatch: { chars: 5277, bytes: 5281 },
explorer: { chars: 4041, bytes: 4059 },
planner: { chars: 4439, bytes: 4447 },
coder: { chars: 4705, bytes: 4715 },
Expand Down
12 changes: 12 additions & 0 deletions src/prompts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ test("chat system prompt keeps the routing, spawn-brief, and rules sections", ()
expect(prompt).toContain("manage_tasks");
});

test("dispatch card is spawn-first with no parallelization cap", () => {
const prompt = buildChatSystemPrompt();
expect(prompt).toContain("# Spawn");
expect(prompt).toContain("no parallelization cap");
expect(prompt).toMatch(/first assistant turn/i);
expect(prompt).toMatch(/same turn/i);
expect(prompt).toMatch(/same live job/i);
expect(prompt).not.toMatch(/Do not duplicate a live worker/i);
expect(prompt).not.toMatch(/diagnostic fleet/i);
expect(prompt).not.toMatch(/single explorer worker/i);
});

const envBase: EnvironmentInfo = {
cwd: "/tmp/proj",
platform: "test",
Expand Down
Loading