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
35 changes: 35 additions & 0 deletions agents/planner/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# @corbits/code-agent-planner

## What this is

Ready `@corbits/code-agent-planner` agent + independently importable components:
`agent`, `defineAgent`, `director`, `tools`, `systemPrompt`, `config`.

## Consume (runLocal)

```ts
import { agent } from "@corbits/code-agent-planner";
const run = runLocal(defining(agent), env);
```

## Consume (deploy runWorkflow / hub / sidecar)

Hand the same `AgentDefinition` to a workflow — the package never exports a
workflow itself.

## Remix components

```ts
import { director, tools, systemPrompt, config } from "@corbits/code-agent-planner";
defineAgent({ director, ... }); // or swap tools / systemPrompt / config
```

Each of `director`, `tools`, `systemPrompt`, and `config` is a named,
independently importable part.

## Single authority

`prompt.ts` `systemPrompt.build()` is byte-stable (the raw card, no formatting).
`toolset.ts` `tools` literal equals the `REVIEW_TOOLS` surface constant in
`src/agent/directors/tool-sets.ts`; drift is enforced by the in-tree drift-guard
`src/agent/directors/planner/package.test.ts`.
13 changes: 13 additions & 0 deletions agents/planner/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "@corbits/code-agent-planner",
"version": "0.1.0",
"private": true,
"type": "module",
"license": "SEE LICENSE IN LICENSE.md",
"exports": {
".": {
"types": "./src/index.ts",
"default": "./src/index.ts"
}
}
}
17 changes: 17 additions & 0 deletions agents/planner/src/agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {
defineAgent as coreDefineAgent,
type AgentDefinition,
} from "@intx/agent";
import { systemPrompt } from "./prompt.js";

export const agent: AgentDefinition = defineAgent();

export function defineAgent(): AgentDefinition {
return coreDefineAgent({
id: "planner",
systemPrompt: systemPrompt.build(),
tools: [],
capabilities: [],
inference: { sources: [] },
});
}
9 changes: 9 additions & 0 deletions agents/planner/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const config = {
spawn: { maySpawn: false },
tier: "leaf",
modelRole: "plan",
} as const satisfies {
spawn: { maySpawn: boolean };
tier: string;
modelRole: string;
};
22 changes: 22 additions & 0 deletions agents/planner/src/director.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { tools } from "./toolset.js";
import { systemPrompt } from "./prompt.js";
import { config } from "./config.js";

export const director = {
id: "planner",
primaryIntent:
"Author requirements (PRD.md), solution scopes (SOLUTION_SCOPE.md), and ordered build plans (BUILD_PLAN.md)",
outOfLane: [
"shipping product implementation code",
"fleet orchestration or spawning",
"pure code defect review",
"becoming Coder or Reviewer as primary",
],
description:
"Planning specialist — PRD.md, SOLUTION_SCOPE.md, and BUILD_PLAN.md authoring",
systemPrompt: systemPrompt.build(),
tools: { allow: [...tools] },
spawn: config.spawn,
tier: config.tier,
modelRole: config.modelRole,
} as const;
5 changes: 5 additions & 0 deletions agents/planner/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { agent, defineAgent } from "./agent.js";
export { director } from "./director.js";
export { tools } from "./toolset.js";
export { systemPrompt } from "./prompt.js";
export { config } from "./config.js";
Original file line number Diff line number Diff line change
@@ -1,32 +1,10 @@
import type { DirectorPackage } from "../types.js";
import { BUILD_TOOLS } from "../tool-sets.js";
// The app formats the identity header via formatDirectorSystemPrompt.

/**
* Planner worker: PRD / solution-scope / build-plan author.
* Produces requirements (PRD.md), solution scopes (SOLUTION_SCOPE.md),
* and concrete ordered build plans (BUILD_PLAN.md).
*/
export const plannerPackage: DirectorPackage = {
id: "planner",
primaryIntent:
"Author requirements (PRD.md), solution scopes (SOLUTION_SCOPE.md), and ordered build plans (BUILD_PLAN.md)",
outOfLane: [
"shipping product implementation code",
"fleet orchestration or spawning",
"pure code defect review",
"becoming Coder or Reviewer as primary",
],
description:
"Planning specialist — PRD.md, SOLUTION_SCOPE.md, and BUILD_PLAN.md authoring",
tools: { allow: BUILD_TOOLS },
spawn: { maySpawn: false },
tier: "leaf",
modelRole: "plan",
systemPrompt: `You are PlannerDirector (Planner), a specialist in Corbits Code.
const CARD = `You are PlannerDirector (Planner), a specialist in Corbits Code.

PRIMARY INTENT: author concrete, agent-proof engineering artifacts and plans. You are the planning lane only — not Coder, not Reviewer, not an orchestrator. Do not ship product implementation code yourself; author the plan and artifacts that Coder can execute without guessing.

Core artifacts:
Sawyer-skills discipline & core artifacts:
1. PRD.md (Requirements):
- Problem statement & user/operator value.
- User stories and detailed acceptance criteria.
Expand All @@ -48,5 +26,9 @@ Workflow:
3. Produce the plan: author the requested artifacts (PRD.md / SOLUTION_SCOPE.md / BUILD_PLAN.md when requested, or include the structured plan directly in Findings).
4. Report: use the standard Summary / Findings / Blockers / Paths report envelope. Findings must carry the complete ordered plan, acceptance criteria, non-goals, and risks.

OUT OF LANE: shipping product implementation code, executing test suites for product verification, fleet orchestration or spawning, becoming Coder or Reviewer as primary.`,
OUT OF LANE: shipping product implementation code, executing test suites for product verification, fleet orchestration or spawning, becoming Coder or Reviewer as primary.`;

export const systemPrompt = {
theme: "planner",
build: (): string => CARD,
};
15 changes: 15 additions & 0 deletions agents/planner/src/toolset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export const tools: readonly string[] = [
"read_file",
"grep",
"search_files",
"list_dir",
"lsp",
"run_shell",
"web_fetch",
"web_search",
"skill_search",
"use_skill",
"write_file",
"edit_file",
"delete_file",
] as const;
7 changes: 7 additions & 0 deletions agents/planner/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"noEmit": true
},
"include": ["src/**/*.ts"]
}
5 changes: 5 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@
"arktype": "catalog:",
"isomorphic-git": "catalog:",
"@corbits/code-agent-designer": "workspace:*",
"@corbits/code-agent-reviewer": "workspace:*"
"@corbits/code-agent-reviewer": "workspace:*",
"@corbits/code-agent-planner": "workspace:*"
},
"devDependencies": {
"@intx/inference-testing": "0.3.0",
Expand Down
8 changes: 8 additions & 0 deletions scripts/dead-export-allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ agents/reviewer/src/index.ts: systemPrompt
agents/reviewer/src/index.ts: config
agents/reviewer/src/config.ts: satisfies
agents/reviewer/src/config.ts: boolean
agents/planner/src/index.ts: agent
agents/planner/src/index.ts: defineAgent
agents/planner/src/index.ts: director
agents/planner/src/index.ts: tools
agents/planner/src/index.ts: systemPrompt
agents/planner/src/index.ts: config
agents/planner/src/config.ts: satisfies
agents/planner/src/config.ts: boolean

# Versioned prompt-variance package public surface (CL-8269 lane,
# agent-owned). Family rows data re-exported through the package entry point;
Expand Down
47 changes: 47 additions & 0 deletions src/agent/directors/planner/package.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { describe, expect, test } from "bun:test";

import {
director,
tools,
config,
systemPrompt,
} from "@corbits/code-agent-planner";
import { REVIEW_TOOLS } from "../tool-sets.js";
import { DIRECTOR_REGISTRY } from "../registry.js";
import type { DirectorPackage } from "../types.js";

describe("plannerPackage", () => {
test("workspace package satisfies the director contract and feeds the registry", () => {
const asDirector: DirectorPackage = director;
expect(asDirector.id).toBe("planner");
expect(DIRECTOR_REGISTRY.planner).toBe(director);
expect([...director.tools.allow]).toEqual([...REVIEW_TOOLS]);
expect(new Set(director.tools.allow).size).toBe(
director.tools.allow.length,
);
});

test("spawn/tier/modelRole match config", () => {
expect(director.spawn).toEqual(config.spawn);
expect(director.tier).toBe(config.tier);
expect(director.modelRole).toBe(config.modelRole);
expect(director.spawn.maySpawn).toBe(false);
});

test("prompt authority is byte-stable", () => {
expect(director.systemPrompt).toBe(systemPrompt.build());
expect(systemPrompt.build()).toBe(systemPrompt.build());
});

test("tools surface matches the tool-sets constant and is leaf-scoped", () => {
expect([...tools]).toEqual([...REVIEW_TOOLS]);
expect(tools).not.toContain("spawn_agent");
expect(tools).not.toContain("ask_operator");
expect(tools).not.toContain("wait_agents");
expect(tools).not.toContain("search_agents");
});

test("tools allowlist has no duplicates", () => {
expect(new Set([...tools]).size).toBe(tools.length);
});
});
4 changes: 2 additions & 2 deletions src/agent/directors/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { AgentProfile, CapabilityFilter } from "../profile-types.js";
import { director as artistDirector } from "@corbits/code-agent-artist";
import { coderPackage } from "./coder/package.js";
import { explorerPackage } from "./explorer/package.js";
import { plannerPackage } from "./planner/package.js";
import { director as plannerDirector } from "@corbits/code-agent-planner";
import { qaLeadPackage } from "./qa-lead/package.js";
import { director as reviewerDirector } from "@corbits/code-agent-reviewer";
import { formatDirectorSystemPrompt } from "./identity.js";
Expand Down Expand Up @@ -39,7 +39,7 @@ export const DIRECTOR_REGISTRY: Readonly<Record<DirectorId, DirectorPackage>> =
{
dispatch: dispatchDirector,
explorer: explorerPackage,
planner: plannerPackage,
planner: plannerDirector,
coder: coderPackage,
reviewer: reviewerDirector,
designer: designerDirector,
Expand Down
Loading