From b20f38efe33cac09c6f1fcf6a232c00b076a394a Mon Sep 17 00:00:00 2001 From: Sawyer Date: Sun, 4 Oct 2026 23:53:45 -0700 Subject: [PATCH 1/8] feat(shakespeare): ship shakespeare as a workspace agent package Extract @corbits/agent-shakespeare following the agents/warden precedent: byte-identical prompt, order-identical docs tools, registry imports the workspace dep, in-tree package.ts deleted with no shim, co-located drift test, tsconfig paths + workspaces dep + bun.lock. Fixes CL-9807 --- agents/shakespeare/package.json | 13 ++++++ .../shakespeare/src/index.ts | 46 +++++++++++++++++-- bun.lock | 5 ++ package.json | 1 + src/agent/directors/registry.ts | 2 +- .../directors/shakespeare/package.test.ts | 27 +++++++++++ tsconfig.json | 1 + 7 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 agents/shakespeare/package.json rename src/agent/directors/shakespeare/package.ts => agents/shakespeare/src/index.ts (78%) create mode 100644 src/agent/directors/shakespeare/package.test.ts diff --git a/agents/shakespeare/package.json b/agents/shakespeare/package.json new file mode 100644 index 000000000..067ea8d33 --- /dev/null +++ b/agents/shakespeare/package.json @@ -0,0 +1,13 @@ +{ + "name": "@corbits/agent-shakespeare", + "version": "0.1.0", + "private": true, + "type": "module", + "license": "SEE LICENSE IN LICENSE.md", + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + } +} diff --git a/src/agent/directors/shakespeare/package.ts b/agents/shakespeare/src/index.ts similarity index 78% rename from src/agent/directors/shakespeare/package.ts rename to agents/shakespeare/src/index.ts index 5bf21267a..aef1ca289 100644 --- a/src/agent/directors/shakespeare/package.ts +++ b/agents/shakespeare/src/index.ts @@ -1,12 +1,48 @@ -import type { DirectorPackage } from "../types.js"; -import { DOCS_TOOLS } from "../tool-sets.js"; - /** * Shakespeare worker (CL-7029). * Docs maintenance — PRODUCT / ARCHITECTURE / IMPLEMENTATION only; docs core baked in. * Package id/path stays `shakespeare` (global rename is out of scope). + * + * Ships as the @corbits/agent-shakespeare workspace package: the tool allowlist + * lives here so the package stays importable without the app. Drift against + * the app build surface fails src/agent/directors/shakespeare/package.test.ts. */ -export const shakespearePackage: DirectorPackage = { +export type AgentPackage = { + readonly id: "shakespeare"; + readonly primaryIntent: string; + readonly outOfLane: readonly string[]; + readonly description: string; + readonly systemPrompt: string; + /** Unset — shakespeare never attaches skill bodies at spawn. */ + readonly attachedSkills?: readonly string[]; + /** Unset — shakespeare declares no skill scope. */ + readonly optionalSkills?: readonly string[]; + readonly tools: { + readonly allow: readonly string[]; + }; + readonly spawn: { + readonly maySpawn: false; + }; + readonly modelRole: "docs"; + readonly tier: "leaf"; +}; + +const SHAKESPEARE_TOOLS = [ + "read_file", + "grep", + "search_files", + "list_dir", + "lsp", + "web_fetch", + "web_search", + "skill_search", + "use_skill", + "write_file", + "edit_file", + "delete_file", +] as const; + +export const shakespearePackage: AgentPackage = { id: "shakespeare", primaryIntent: "Maintain product, architecture, and implementation docs", outOfLane: [ @@ -73,7 +109,7 @@ Confirm what changed and where. Summarize consistency/gap follow-ups. Map each s DONE GATE: Stop when every success_criteria item from the brief is met OR explicitly blocked under Blockers. Do not invent architecture campaigns or expand the brief after criteria are satisfied. If the ask needs product code, review, or brand/DESIGN.md, report Blockers — do not become Coder, Reviewer, or Designer. OUT OF LANE: shipping product features, pure code review, orchestration, treating docs as optional, DESIGN.md ownership, becoming Coder or Reviewer as primary.`, - tools: { allow: DOCS_TOOLS }, + tools: { allow: [...SHAKESPEARE_TOOLS] }, spawn: { maySpawn: false }, tier: "leaf", modelRole: "docs", diff --git a/bun.lock b/bun.lock index 95f06b9f9..c55b1eedc 100644 --- a/bun.lock +++ b/bun.lock @@ -5,6 +5,7 @@ "": { "name": "@corbits/code", "dependencies": { + "@corbits/agent-shakespeare": "workspace:*", "@corbits/codex-provider": "0.1.1", "@corbits/oauth-core": "0.2.0", "@corbits/openai-responses": "0.2.1", @@ -52,6 +53,9 @@ }, "agents/artist": { "name": "@corbits/code-agent-artist", + }, + "agents/shakespeare": { + "name": "@corbits/agent-shakespeare", "version": "0.1.0", }, "packages/first-class-providers": { @@ -246,6 +250,7 @@ "@better-fetch/fetch": ["@better-fetch/fetch@1.3.2", "", {}, "sha512-Gs7n99b5tqUC6cQAPbV0uED3IraHB6xQbHLQ/C3l7ZFafHScOx9pQ+DYmP5blbLFShVWLqxNUlI9wi4xU/X+ow=="], "@corbits/code-agent-artist": ["@corbits/code-agent-artist@workspace:agents/artist"], + "@corbits/agent-shakespeare": ["@corbits/agent-shakespeare@workspace:agents/shakespeare"], "@corbits/codex-provider": ["@corbits/codex-provider@0.1.1", "", { "dependencies": { "arktype": "^2.2.3" }, "peerDependencies": { "@corbits/oauth-core": "^0.2.0", "@corbits/openai-responses": "^0.2.0", "@intx/inference": "^0.4.0", "@intx/types": "^0.4.0" } }, "sha512-MiGA5djQNtRpHqLvJAGdFgHEbUl808AbveMPwt7krLjOH0i20DyElpitHPZF3ltCXkFMhcKIoyTAEpRDqeB/Rw=="], diff --git a/package.json b/package.json index c427a0851..b1ca7adc5 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "tar": "^7.5.1" }, "dependencies": { + "@corbits/agent-shakespeare": "workspace:*", "@corbits/codex-provider": "0.1.1", "@corbits/oauth-core": "0.2.0", "@corbits/openai-responses": "0.2.1", diff --git a/src/agent/directors/registry.ts b/src/agent/directors/registry.ts index 18231564c..0f2dfc59e 100644 --- a/src/agent/directors/registry.ts +++ b/src/agent/directors/registry.ts @@ -1,3 +1,4 @@ +import { shakespearePackage } from "@corbits/agent-shakespeare"; import type { AgentProfile, CapabilityFilter } from "../profile-types.js"; import { director as artistDirector } from "@corbits/code-agent-artist"; import { coderPackage } from "./coder/package.js"; @@ -8,7 +9,6 @@ import { plannerPackage } from "./planner/package.js"; import { proberPackage } from "./prober/package.js"; import { qaLeadPackage } from "./qa-lead/package.js"; import { reviewerPackage } from "./reviewer/package.js"; -import { shakespearePackage } from "./shakespeare/package.js"; import { wardenPackage } from "./warden/package.js"; import { formatDirectorSystemPrompt } from "./identity.js"; import { diff --git a/src/agent/directors/shakespeare/package.test.ts b/src/agent/directors/shakespeare/package.test.ts new file mode 100644 index 000000000..0f86e2f82 --- /dev/null +++ b/src/agent/directors/shakespeare/package.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, test } from "bun:test"; + +import { shakespearePackage } from "@corbits/agent-shakespeare"; +import { DOCS_TOOLS } from "../tool-sets.js"; +import { DIRECTOR_REGISTRY } from "../registry.js"; +import type { DirectorPackage } from "../types.js"; + +describe("shakespearePackage", () => { + test("workspace package satisfies the director contract and feeds the registry", () => { + const asDirector: DirectorPackage = shakespearePackage; + expect(asDirector.id).toBe("shakespeare"); + expect(DIRECTOR_REGISTRY.shakespeare).toBe(shakespearePackage); + expect([...shakespearePackage.tools.allow]).toEqual([...DOCS_TOOLS]); + }); + + test("extracted copy stays docs-scoped and non-spawning", () => { + expect(shakespearePackage.tools.allow).toContain("write_file"); + expect(shakespearePackage.tools.allow).toContain("edit_file"); + expect(shakespearePackage.tools.allow).toContain("delete_file"); + expect(shakespearePackage.tools.allow).not.toContain("run_shell"); + expect(shakespearePackage.tools.allow).not.toContain("spawn_agent"); + expect(shakespearePackage.tools.allow).not.toContain("ask_operator"); + expect(shakespearePackage.spawn.maySpawn).toBe(false); + expect(shakespearePackage.tier).toBe("leaf"); + expect(shakespearePackage.modelRole).toBe("docs"); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index 19b14b736..bd29c13f3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "baseUrl": ".", "paths": { "@corbits/code-agent-artist": ["./agents/artist/src/index.ts"], + "@corbits/agent-shakespeare": ["./agents/shakespeare/src/index.ts"], "@corbits/provider-opencode-go": ["./packages/opencode-go/src/index.ts"], "@corbits/first-class-providers": [ "./packages/first-class-providers/src/index.ts" From 696697ce3911b88fff340ee574ee3fc46c7be076 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Thu, 8 Oct 2026 14:01:00 -0700 Subject: [PATCH 2/8] chore(shakespeare): rename package to @corbits/code-agent-shakespeare --- agents/shakespeare/package.json | 2 +- agents/shakespeare/src/index.ts | 2 +- bun.lock | 6 +++--- package.json | 2 +- src/agent/directors/registry.ts | 2 +- src/agent/directors/shakespeare/package.test.ts | 2 +- tsconfig.json | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/agents/shakespeare/package.json b/agents/shakespeare/package.json index 067ea8d33..299e58e48 100644 --- a/agents/shakespeare/package.json +++ b/agents/shakespeare/package.json @@ -1,5 +1,5 @@ { - "name": "@corbits/agent-shakespeare", + "name": "@corbits/code-agent-shakespeare", "version": "0.1.0", "private": true, "type": "module", diff --git a/agents/shakespeare/src/index.ts b/agents/shakespeare/src/index.ts index aef1ca289..990b0c1ab 100644 --- a/agents/shakespeare/src/index.ts +++ b/agents/shakespeare/src/index.ts @@ -3,7 +3,7 @@ * Docs maintenance — PRODUCT / ARCHITECTURE / IMPLEMENTATION only; docs core baked in. * Package id/path stays `shakespeare` (global rename is out of scope). * - * Ships as the @corbits/agent-shakespeare workspace package: the tool allowlist + * Ships as the @corbits/code-agent-shakespeare workspace package: the tool allowlist * lives here so the package stays importable without the app. Drift against * the app build surface fails src/agent/directors/shakespeare/package.test.ts. */ diff --git a/bun.lock b/bun.lock index c55b1eedc..2c7d161d6 100644 --- a/bun.lock +++ b/bun.lock @@ -5,7 +5,7 @@ "": { "name": "@corbits/code", "dependencies": { - "@corbits/agent-shakespeare": "workspace:*", + "@corbits/code-agent-shakespeare": "workspace:*", "@corbits/codex-provider": "0.1.1", "@corbits/oauth-core": "0.2.0", "@corbits/openai-responses": "0.2.1", @@ -55,7 +55,7 @@ "name": "@corbits/code-agent-artist", }, "agents/shakespeare": { - "name": "@corbits/agent-shakespeare", + "name": "@corbits/code-agent-shakespeare", "version": "0.1.0", }, "packages/first-class-providers": { @@ -250,7 +250,7 @@ "@better-fetch/fetch": ["@better-fetch/fetch@1.3.2", "", {}, "sha512-Gs7n99b5tqUC6cQAPbV0uED3IraHB6xQbHLQ/C3l7ZFafHScOx9pQ+DYmP5blbLFShVWLqxNUlI9wi4xU/X+ow=="], "@corbits/code-agent-artist": ["@corbits/code-agent-artist@workspace:agents/artist"], - "@corbits/agent-shakespeare": ["@corbits/agent-shakespeare@workspace:agents/shakespeare"], + "@corbits/code-agent-shakespeare": ["@corbits/code-agent-shakespeare@workspace:agents/shakespeare"], "@corbits/codex-provider": ["@corbits/codex-provider@0.1.1", "", { "dependencies": { "arktype": "^2.2.3" }, "peerDependencies": { "@corbits/oauth-core": "^0.2.0", "@corbits/openai-responses": "^0.2.0", "@intx/inference": "^0.4.0", "@intx/types": "^0.4.0" } }, "sha512-MiGA5djQNtRpHqLvJAGdFgHEbUl808AbveMPwt7krLjOH0i20DyElpitHPZF3ltCXkFMhcKIoyTAEpRDqeB/Rw=="], diff --git a/package.json b/package.json index b1ca7adc5..1dd5c2cb2 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "tar": "^7.5.1" }, "dependencies": { - "@corbits/agent-shakespeare": "workspace:*", + "@corbits/code-agent-shakespeare": "workspace:*", "@corbits/codex-provider": "0.1.1", "@corbits/oauth-core": "0.2.0", "@corbits/openai-responses": "0.2.1", diff --git a/src/agent/directors/registry.ts b/src/agent/directors/registry.ts index 0f2dfc59e..19daabf9a 100644 --- a/src/agent/directors/registry.ts +++ b/src/agent/directors/registry.ts @@ -1,4 +1,4 @@ -import { shakespearePackage } from "@corbits/agent-shakespeare"; +import { shakespearePackage } from "@corbits/code-agent-shakespeare"; import type { AgentProfile, CapabilityFilter } from "../profile-types.js"; import { director as artistDirector } from "@corbits/code-agent-artist"; import { coderPackage } from "./coder/package.js"; diff --git a/src/agent/directors/shakespeare/package.test.ts b/src/agent/directors/shakespeare/package.test.ts index 0f86e2f82..73c4ea50a 100644 --- a/src/agent/directors/shakespeare/package.test.ts +++ b/src/agent/directors/shakespeare/package.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test"; -import { shakespearePackage } from "@corbits/agent-shakespeare"; +import { shakespearePackage } from "@corbits/code-agent-shakespeare"; import { DOCS_TOOLS } from "../tool-sets.js"; import { DIRECTOR_REGISTRY } from "../registry.js"; import type { DirectorPackage } from "../types.js"; diff --git a/tsconfig.json b/tsconfig.json index bd29c13f3..df0b1cca4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,7 +6,7 @@ "baseUrl": ".", "paths": { "@corbits/code-agent-artist": ["./agents/artist/src/index.ts"], - "@corbits/agent-shakespeare": ["./agents/shakespeare/src/index.ts"], + "@corbits/code-agent-shakespeare": ["./agents/shakespeare/src/index.ts"], "@corbits/provider-opencode-go": ["./packages/opencode-go/src/index.ts"], "@corbits/first-class-providers": [ "./packages/first-class-providers/src/index.ts" From ace6302af08ffd33d522798641d4153522e9cf73 Mon Sep 17 00:00:00 2001 From: Sawyer Date: Thu, 8 Oct 2026 19:44:56 -0700 Subject: [PATCH 3/8] feat(agent-shakespeare): adopt uniform reusable agent template shape --- agents/shakespeare/README.md | 35 +++++ agents/shakespeare/src/agent.ts | 24 ++++ agents/shakespeare/src/config.ts | 10 ++ agents/shakespeare/src/director.ts | 24 ++++ agents/shakespeare/src/index.ts | 124 ++---------------- agents/shakespeare/src/prompt.ts | 69 ++++++++++ agents/shakespeare/src/toolset.ts | 19 +++ agents/shakespeare/tsconfig.json | 7 + bun.lock | 1 - package.json | 1 - src/agent/directors/registry.ts | 4 +- .../directors/shakespeare/package.test.ts | 49 +++++-- 12 files changed, 233 insertions(+), 134 deletions(-) create mode 100644 agents/shakespeare/README.md create mode 100644 agents/shakespeare/src/agent.ts create mode 100644 agents/shakespeare/src/config.ts create mode 100644 agents/shakespeare/src/director.ts create mode 100644 agents/shakespeare/src/prompt.ts create mode 100644 agents/shakespeare/src/toolset.ts create mode 100644 agents/shakespeare/tsconfig.json diff --git a/agents/shakespeare/README.md b/agents/shakespeare/README.md new file mode 100644 index 000000000..e8596c7b8 --- /dev/null +++ b/agents/shakespeare/README.md @@ -0,0 +1,35 @@ +# @corbits/code-agent-shakespeare + +## What this is + +Ready `@corbits/code-agent-shakespeare` agent + independently importable components: +`agent`, `defineAgent`, `director`, `tools`, `systemPrompt`, `config`. + +## Consume (runLocal) + +```ts +import { agent } from "@corbits/code-agent-shakespeare"; +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-shakespeare"; +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 `DOCS_TOOLS` surface constant in +`src/agent/directors/tool-sets.ts` (no `run_shell`); drift is enforced by the +in-tree drift-guard `src/agent/directors/shakespeare/package.test.ts`. diff --git a/agents/shakespeare/src/agent.ts b/agents/shakespeare/src/agent.ts new file mode 100644 index 000000000..dc0155b6d --- /dev/null +++ b/agents/shakespeare/src/agent.ts @@ -0,0 +1,24 @@ +import { + defineAgent as coreDefineAgent, + type AgentDefinition, +} from "@intx/agent"; +import { systemPrompt } from "./prompt.js"; + +/** + * Shakespeare ready agent — `agent = defineAgent()` plus the named component + * parts (director/tools/systemPrompt/config) form the whole package surface. + */ +export const agent: AgentDefinition = defineAgent(); + +export function defineAgent(): AgentDefinition { + return coreDefineAgent({ + id: "shakespeare", + systemPrompt: systemPrompt.build(), + tools: [], // tool mounting is consumer/app-side; surface enforced by drift-guard + capabilities: [], + inference: { + sources: [{ provider: "openai", model: "gpt-5" }], + }, + tags: { fleet: "0.3.36", lane: "shakespeare" }, + }); +} diff --git a/agents/shakespeare/src/config.ts b/agents/shakespeare/src/config.ts new file mode 100644 index 000000000..f0dc29f2f --- /dev/null +++ b/agents/shakespeare/src/config.ts @@ -0,0 +1,10 @@ +/** Shakespeare worker — docs maintenance (PRODUCT / ARCHITECTURE / IMPLEMENTATION). */ +export const config = { + spawn: { maySpawn: false }, + tier: "leaf", + modelRole: "docs", +} as const satisfies { + spawn: { maySpawn: boolean }; + tier: string; + modelRole: string; +}; diff --git a/agents/shakespeare/src/director.ts b/agents/shakespeare/src/director.ts new file mode 100644 index 000000000..b9032bc69 --- /dev/null +++ b/agents/shakespeare/src/director.ts @@ -0,0 +1,24 @@ +import { tools } from "./toolset.js"; +import { systemPrompt } from "./prompt.js"; +import { config } from "./config.js"; + +/** + * Shakespeare worker director card (CL-7029). Structurally satisfies the app's + * `DirectorPackage` (app-side drift-guard asserts assignability). App-independent. + */ +export const director = { + id: "shakespeare", + primaryIntent: "Maintain product, architecture, and implementation docs", + outOfLane: [ + "shipping product features", + "pure code review", + "orchestration / fleet control", + "acting as reviewer or implementer", + ], + description: "Docs maintenance — PRODUCT / ARCHITECTURE / IMPLEMENTATION", + systemPrompt: systemPrompt.build(), + tools: { allow: [...tools] }, + spawn: config.spawn, + tier: config.tier, + modelRole: config.modelRole, +} as const; diff --git a/agents/shakespeare/src/index.ts b/agents/shakespeare/src/index.ts index 990b0c1ab..95fc4d646 100644 --- a/agents/shakespeare/src/index.ts +++ b/agents/shakespeare/src/index.ts @@ -1,116 +1,8 @@ -/** - * Shakespeare worker (CL-7029). - * Docs maintenance — PRODUCT / ARCHITECTURE / IMPLEMENTATION only; docs core baked in. - * Package id/path stays `shakespeare` (global rename is out of scope). - * - * Ships as the @corbits/code-agent-shakespeare workspace package: the tool allowlist - * lives here so the package stays importable without the app. Drift against - * the app build surface fails src/agent/directors/shakespeare/package.test.ts. - */ -export type AgentPackage = { - readonly id: "shakespeare"; - readonly primaryIntent: string; - readonly outOfLane: readonly string[]; - readonly description: string; - readonly systemPrompt: string; - /** Unset — shakespeare never attaches skill bodies at spawn. */ - readonly attachedSkills?: readonly string[]; - /** Unset — shakespeare declares no skill scope. */ - readonly optionalSkills?: readonly string[]; - readonly tools: { - readonly allow: readonly string[]; - }; - readonly spawn: { - readonly maySpawn: false; - }; - readonly modelRole: "docs"; - readonly tier: "leaf"; -}; - -const SHAKESPEARE_TOOLS = [ - "read_file", - "grep", - "search_files", - "list_dir", - "lsp", - "web_fetch", - "web_search", - "skill_search", - "use_skill", - "write_file", - "edit_file", - "delete_file", -] as const; - -export const shakespearePackage: AgentPackage = { - id: "shakespeare", - primaryIntent: "Maintain product, architecture, and implementation docs", - outOfLane: [ - "shipping product features", - "pure code review", - "orchestration / fleet control", - "acting as reviewer or implementer", - ], - description: "Docs maintenance — PRODUCT / ARCHITECTURE / IMPLEMENTATION", - systemPrompt: `You are ShakespeareDirector (Shakespeare), a specialist in Corbits Code. - -PRIMARY INTENT: maintain PRODUCT.md, ARCHITECTURE.md, and IMPLEMENTATION.md. Route input to the correct doc, detect gaps, surface questions for completeness, and keep cross-doc consistency. You are the docs lane only — not Coder, not Reviewer, not an orchestrator. - -BLINDERS ON: Stay on the brief's success_criteria and the P/A/I docs. Do not wander into product source, DESIGN.md / brand, review severity theater, or fleet discovery. - -# Document types - -**PRODUCT.md** — what we build and why: user value, vision, goals, target users, business justification. - -**ARCHITECTURE.md** — how the system is structured: components, relationships, abstractions, data/control flow, technology-agnostic design decisions. - -**IMPLEMENTATION.md** — concrete tech: libraries, protocols, formats, configuration, deployment specifics. - -# Workflow (docs core) - -## 0. Document discovery - -Before processing input, locate docs (case-insensitive) in repo root and \`docs/\`: -- PRODUCT.md, ARCHITECTURE.md, IMPLEMENTATION.md -- Prefer root when multiple matches exist. -- Defaults when missing: create at repository root. - -Read existing docs first to learn project vocabulary, patterns, constraints, and similar features. - -## 1. Analyze and classify input - -Classify by heuristics and project-specific signals from existing docs (project vocabulary wins when clear): - -- **Product:** user needs, value, market, "users can", goals without how -- **Architecture:** components, interactions, abstractions, tech-agnostic design -- **Implementation:** named technologies, wire formats, config, "uses"/"built on" - -## 2. Route and deepen - -If classification is clear, update the right document. -If ambiguous or multi-category, do not ask only "which document?" — decompose into distinct claims and route each precisely. Prefer context-aware options from existing docs; fall back to general options when docs are empty/minimal. One statement may update multiple docs. Put unresolved targeting questions under Blockers for the parent/operator. - -## 3. Update document - -Read the target, place content (extend section / new section / revise), match existing style. Significant changes (new concept/component/capability, contradiction, top-level decision) trigger steps 4–5. Minor clarifications skip to report. - -## 4. Cross-document consistency (significant only) - -Check sibling docs for implied missing entries (e.g. new architecture with no product justification, product capability with no architecture, implementation naming an undescribed component). Surface targeted questions under Blockers; update docs from answers when provided. - -## 5. Gap detection (significant only) - -Scan for thin sections, undefined references, missing failure modes/constraints, decisions without rationale. Probe with contextual options. If the operator declines further gap probing, stop unless they ask. - -## 6. Report - -Confirm what changed and where. Summarize consistency/gap follow-ups. Map each success_criteria item → pass | fail | blocked. - -DONE GATE: Stop when every success_criteria item from the brief is met OR explicitly blocked under Blockers. Do not invent architecture campaigns or expand the brief after criteria are satisfied. If the ask needs product code, review, or brand/DESIGN.md, report Blockers — do not become Coder, Reviewer, or Designer. - -OUT OF LANE: shipping product features, pure code review, orchestration, treating docs as optional, DESIGN.md ownership, becoming Coder or Reviewer as primary.`, - tools: { allow: [...SHAKESPEARE_TOOLS] }, - spawn: { maySpawn: false }, - tier: "leaf", - modelRole: "docs", -}; +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"; +// No workflow export. The package's `director` structurally satisfies the +// app's DirectorPackage (app-side drift-guard asserts it). No type re-export +// to any Corbits shared package. diff --git a/agents/shakespeare/src/prompt.ts b/agents/shakespeare/src/prompt.ts new file mode 100644 index 000000000..187c1c3d3 --- /dev/null +++ b/agents/shakespeare/src/prompt.ts @@ -0,0 +1,69 @@ +// Shakespeare raw director card (CL-7029). Byte-stable, single authority — +// the app formats the identity header via formatDirectorSystemPrompt. + +const CARD = `You are ShakespeareDirector (Shakespeare), a specialist in Corbits Code. + +PRIMARY INTENT: maintain PRODUCT.md, ARCHITECTURE.md, and IMPLEMENTATION.md. Route input to the correct doc, detect gaps, surface questions for completeness, and keep cross-doc consistency. You are the docs lane only — not Coder, not Reviewer, not an orchestrator. + +BLINDERS ON: Stay on the brief's success_criteria and the P/A/I docs. Do not wander into product source, DESIGN.md / brand, review severity theater, or fleet discovery. + +# Document types + +**PRODUCT.md** — what we build and why: user value, vision, goals, target users, business justification. + +**ARCHITECTURE.md** — how the system is structured: components, relationships, abstractions, data/control flow, technology-agnostic design decisions. + +**IMPLEMENTATION.md** — concrete tech: libraries, protocols, formats, configuration, deployment specifics. + +# Workflow (docs core) + +## 0. Document discovery + +Before processing input, locate docs (case-insensitive) in repo root and \`docs/\`: +- PRODUCT.md, ARCHITECTURE.md, IMPLEMENTATION.md +- Prefer root when multiple matches exist. +- Defaults when missing: create at repository root. + +Read existing docs first to learn project vocabulary, patterns, constraints, and similar features. + +## 1. Analyze and classify input + +Classify by heuristics and project-specific signals from existing docs (project vocabulary wins when clear): + +- **Product:** user needs, value, market, "users can", goals without how +- **Architecture:** components, interactions, abstractions, tech-agnostic design +- **Implementation:** named technologies, wire formats, config, "uses"/"built on" + +## 2. Route and deepen + +If classification is clear, update the right document. +If ambiguous or multi-category, do not ask only "which document?" — decompose into distinct claims and route each precisely. Prefer context-aware options from existing docs; fall back to general options when docs are empty/minimal. One statement may update multiple docs. Put unresolved targeting questions under Blockers for the parent/operator. + +## 3. Update document + +Read the target, place content (extend section / new section / revise), match existing style. Significant changes (new concept/component/capability, contradiction, top-level decision) trigger steps 4–5. Minor clarifications skip to report. + +## 4. Cross-document consistency (significant only) + +Check sibling docs for implied missing entries (e.g. new architecture with no product justification, product capability with no architecture, implementation naming an undescribed component). Surface targeted questions under Blockers; update docs from answers when provided. + +## 5. Gap detection (significant only) + +Scan for thin sections, undefined references, missing failure modes/constraints, decisions without rationale. Probe with contextual options. If the operator declines further gap probing, stop unless they ask. + +## 6. Report + +Confirm what changed and where. Summarize consistency/gap follow-ups. Map each success_criteria item → pass | fail | blocked. + +DONE GATE: Stop when every success_criteria item from the brief is met OR explicitly blocked under Blockers. Do not invent architecture campaigns or expand the brief after criteria are satisfied. If the ask needs product code, review, or brand/DESIGN.md, report Blockers — do not become Coder, Reviewer, or Designer. + +OUT OF LANE: shipping product features, pure code review, orchestration, treating docs as optional, DESIGN.md ownership, becoming Coder or Reviewer as primary.`; + +/** + * Byte-stable system prompt builder. `theme` is the stable voice identifier; + * `build()` returns the identical raw card on every call (no env/interpolation). + */ +export const systemPrompt = { + theme: "shakespeare", + build: (): string => CARD, +}; diff --git a/agents/shakespeare/src/toolset.ts b/agents/shakespeare/src/toolset.ts new file mode 100644 index 000000000..41cfa596c --- /dev/null +++ b/agents/shakespeare/src/toolset.ts @@ -0,0 +1,19 @@ +// Shakespeare worker: docs maintenance — PRODUCT / ARCHITECTURE / +// IMPLEMENTATION only. Docs lane uses DOCS_TOOLS: no run_shell. + +const SHAKESPEARE_TOOLS = [ + "read_file", + "grep", + "search_files", + "list_dir", + "lsp", + "web_fetch", + "web_search", + "skill_search", + "use_skill", + "write_file", + "edit_file", + "delete_file", +] as const; + +export const tools: readonly string[] = [...SHAKESPEARE_TOOLS]; diff --git a/agents/shakespeare/tsconfig.json b/agents/shakespeare/tsconfig.json new file mode 100644 index 000000000..0d7100cbc --- /dev/null +++ b/agents/shakespeare/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "noEmit": true + }, + "include": ["src/**/*.ts"] +} diff --git a/bun.lock b/bun.lock index 2c7d161d6..71a4669c4 100644 --- a/bun.lock +++ b/bun.lock @@ -5,7 +5,6 @@ "": { "name": "@corbits/code", "dependencies": { - "@corbits/code-agent-shakespeare": "workspace:*", "@corbits/codex-provider": "0.1.1", "@corbits/oauth-core": "0.2.0", "@corbits/openai-responses": "0.2.1", diff --git a/package.json b/package.json index 1dd5c2cb2..c427a0851 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,6 @@ "tar": "^7.5.1" }, "dependencies": { - "@corbits/code-agent-shakespeare": "workspace:*", "@corbits/codex-provider": "0.1.1", "@corbits/oauth-core": "0.2.0", "@corbits/openai-responses": "0.2.1", diff --git a/src/agent/directors/registry.ts b/src/agent/directors/registry.ts index 19daabf9a..2c5ed6b65 100644 --- a/src/agent/directors/registry.ts +++ b/src/agent/directors/registry.ts @@ -1,4 +1,4 @@ -import { shakespearePackage } from "@corbits/code-agent-shakespeare"; +import { director as shakespeareDirector } from "@corbits/code-agent-shakespeare"; import type { AgentProfile, CapabilityFilter } from "../profile-types.js"; import { director as artistDirector } from "@corbits/code-agent-artist"; import { coderPackage } from "./coder/package.js"; @@ -45,7 +45,7 @@ export const DIRECTOR_REGISTRY: Readonly> = designer: designerPackage, artist: artistDirector, warden: wardenPackage, - shakespeare: shakespearePackage, + shakespeare: shakespeareDirector, prober: proberPackage, "qa-lead": qaLeadPackage, }; diff --git a/src/agent/directors/shakespeare/package.test.ts b/src/agent/directors/shakespeare/package.test.ts index 73c4ea50a..f1f4e8497 100644 --- a/src/agent/directors/shakespeare/package.test.ts +++ b/src/agent/directors/shakespeare/package.test.ts @@ -1,27 +1,48 @@ import { describe, expect, test } from "bun:test"; -import { shakespearePackage } from "@corbits/code-agent-shakespeare"; +import { + director, + tools, + config, + systemPrompt, +} from "@corbits/code-agent-shakespeare"; import { DOCS_TOOLS } from "../tool-sets.js"; import { DIRECTOR_REGISTRY } from "../registry.js"; import type { DirectorPackage } from "../types.js"; describe("shakespearePackage", () => { test("workspace package satisfies the director contract and feeds the registry", () => { - const asDirector: DirectorPackage = shakespearePackage; + const asDirector: DirectorPackage = director; expect(asDirector.id).toBe("shakespeare"); - expect(DIRECTOR_REGISTRY.shakespeare).toBe(shakespearePackage); - expect([...shakespearePackage.tools.allow]).toEqual([...DOCS_TOOLS]); + expect(DIRECTOR_REGISTRY.shakespeare).toBe(director); + expect([...director.tools.allow]).toEqual([...DOCS_TOOLS]); + expect(new Set(director.tools.allow).size).toBe( + director.tools.allow.length, + ); }); - test("extracted copy stays docs-scoped and non-spawning", () => { - expect(shakespearePackage.tools.allow).toContain("write_file"); - expect(shakespearePackage.tools.allow).toContain("edit_file"); - expect(shakespearePackage.tools.allow).toContain("delete_file"); - expect(shakespearePackage.tools.allow).not.toContain("run_shell"); - expect(shakespearePackage.tools.allow).not.toContain("spawn_agent"); - expect(shakespearePackage.tools.allow).not.toContain("ask_operator"); - expect(shakespearePackage.spawn.maySpawn).toBe(false); - expect(shakespearePackage.tier).toBe("leaf"); - expect(shakespearePackage.modelRole).toBe("docs"); + 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("docs surface omits run_shell and stays leaf-scoped", () => { + expect([...tools]).toEqual([...DOCS_TOOLS]); + expect(tools).not.toContain("run_shell"); + 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); }); }); From d424a5bc44230b5c45286094fee09b96f2d66dbf Mon Sep 17 00:00:00 2001 From: Sawyer Date: Thu, 8 Oct 2026 20:21:13 -0700 Subject: [PATCH 4/8] style(agent-shakespeare): strip redundant commentary from extracted package --- agents/shakespeare/src/agent.ts | 4 ---- agents/shakespeare/src/director.ts | 4 ---- agents/shakespeare/src/index.ts | 3 --- 3 files changed, 11 deletions(-) diff --git a/agents/shakespeare/src/agent.ts b/agents/shakespeare/src/agent.ts index dc0155b6d..1a69bfea5 100644 --- a/agents/shakespeare/src/agent.ts +++ b/agents/shakespeare/src/agent.ts @@ -4,10 +4,6 @@ import { } from "@intx/agent"; import { systemPrompt } from "./prompt.js"; -/** - * Shakespeare ready agent — `agent = defineAgent()` plus the named component - * parts (director/tools/systemPrompt/config) form the whole package surface. - */ export const agent: AgentDefinition = defineAgent(); export function defineAgent(): AgentDefinition { diff --git a/agents/shakespeare/src/director.ts b/agents/shakespeare/src/director.ts index b9032bc69..f65818174 100644 --- a/agents/shakespeare/src/director.ts +++ b/agents/shakespeare/src/director.ts @@ -2,10 +2,6 @@ import { tools } from "./toolset.js"; import { systemPrompt } from "./prompt.js"; import { config } from "./config.js"; -/** - * Shakespeare worker director card (CL-7029). Structurally satisfies the app's - * `DirectorPackage` (app-side drift-guard asserts assignability). App-independent. - */ export const director = { id: "shakespeare", primaryIntent: "Maintain product, architecture, and implementation docs", diff --git a/agents/shakespeare/src/index.ts b/agents/shakespeare/src/index.ts index 95fc4d646..c2c15f6c6 100644 --- a/agents/shakespeare/src/index.ts +++ b/agents/shakespeare/src/index.ts @@ -3,6 +3,3 @@ export { director } from "./director.js"; export { tools } from "./toolset.js"; export { systemPrompt } from "./prompt.js"; export { config } from "./config.js"; -// No workflow export. The package's `director` structurally satisfies the -// app's DirectorPackage (app-side drift-guard asserts it). No type re-export -// to any Corbits shared package. From 8dd1fb0196772cd25c13da642b6c2947fcb362ea Mon Sep 17 00:00:00 2001 From: Sawyer Date: Thu, 8 Oct 2026 20:21:53 -0700 Subject: [PATCH 5/8] style(agent-shakespeare): strip redundant commentary from extracted package --- agents/shakespeare/src/agent.ts | 4 ++-- agents/shakespeare/src/config.ts | 3 +-- agents/shakespeare/src/director.ts | 2 +- agents/shakespeare/src/index.ts | 2 +- agents/shakespeare/src/prompt.ts | 7 +------ agents/shakespeare/src/toolset.ts | 5 +---- 6 files changed, 7 insertions(+), 16 deletions(-) diff --git a/agents/shakespeare/src/agent.ts b/agents/shakespeare/src/agent.ts index 1a69bfea5..590d28f54 100644 --- a/agents/shakespeare/src/agent.ts +++ b/agents/shakespeare/src/agent.ts @@ -10,11 +10,11 @@ export function defineAgent(): AgentDefinition { return coreDefineAgent({ id: "shakespeare", systemPrompt: systemPrompt.build(), - tools: [], // tool mounting is consumer/app-side; surface enforced by drift-guard + tools: [], capabilities: [], inference: { sources: [{ provider: "openai", model: "gpt-5" }], }, tags: { fleet: "0.3.36", lane: "shakespeare" }, }); -} +} \ No newline at end of file diff --git a/agents/shakespeare/src/config.ts b/agents/shakespeare/src/config.ts index f0dc29f2f..b6bd09a7b 100644 --- a/agents/shakespeare/src/config.ts +++ b/agents/shakespeare/src/config.ts @@ -1,4 +1,3 @@ -/** Shakespeare worker — docs maintenance (PRODUCT / ARCHITECTURE / IMPLEMENTATION). */ export const config = { spawn: { maySpawn: false }, tier: "leaf", @@ -7,4 +6,4 @@ export const config = { spawn: { maySpawn: boolean }; tier: string; modelRole: string; -}; +}; \ No newline at end of file diff --git a/agents/shakespeare/src/director.ts b/agents/shakespeare/src/director.ts index f65818174..e90a1d4cc 100644 --- a/agents/shakespeare/src/director.ts +++ b/agents/shakespeare/src/director.ts @@ -17,4 +17,4 @@ export const director = { spawn: config.spawn, tier: config.tier, modelRole: config.modelRole, -} as const; +} as const; \ No newline at end of file diff --git a/agents/shakespeare/src/index.ts b/agents/shakespeare/src/index.ts index c2c15f6c6..e87040867 100644 --- a/agents/shakespeare/src/index.ts +++ b/agents/shakespeare/src/index.ts @@ -2,4 +2,4 @@ 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"; +export { config } from "./config.js"; \ No newline at end of file diff --git a/agents/shakespeare/src/prompt.ts b/agents/shakespeare/src/prompt.ts index 187c1c3d3..572253471 100644 --- a/agents/shakespeare/src/prompt.ts +++ b/agents/shakespeare/src/prompt.ts @@ -1,5 +1,4 @@ -// Shakespeare raw director card (CL-7029). Byte-stable, single authority — -// the app formats the identity header via formatDirectorSystemPrompt. +// The app formats the identity header via formatDirectorSystemPrompt. const CARD = `You are ShakespeareDirector (Shakespeare), a specialist in Corbits Code. @@ -59,10 +58,6 @@ DONE GATE: Stop when every success_criteria item from the brief is met OR explic OUT OF LANE: shipping product features, pure code review, orchestration, treating docs as optional, DESIGN.md ownership, becoming Coder or Reviewer as primary.`; -/** - * Byte-stable system prompt builder. `theme` is the stable voice identifier; - * `build()` returns the identical raw card on every call (no env/interpolation). - */ export const systemPrompt = { theme: "shakespeare", build: (): string => CARD, diff --git a/agents/shakespeare/src/toolset.ts b/agents/shakespeare/src/toolset.ts index 41cfa596c..b954e1031 100644 --- a/agents/shakespeare/src/toolset.ts +++ b/agents/shakespeare/src/toolset.ts @@ -1,6 +1,3 @@ -// Shakespeare worker: docs maintenance — PRODUCT / ARCHITECTURE / -// IMPLEMENTATION only. Docs lane uses DOCS_TOOLS: no run_shell. - const SHAKESPEARE_TOOLS = [ "read_file", "grep", @@ -16,4 +13,4 @@ const SHAKESPEARE_TOOLS = [ "delete_file", ] as const; -export const tools: readonly string[] = [...SHAKESPEARE_TOOLS]; +export const tools: readonly string[] = [...SHAKESPEARE_TOOLS]; \ No newline at end of file From 11376df9e706ff26ed045fff4a6c5fda7a6f5fc9 Mon Sep 17 00:00:00 2001 From: "user.email" Date: Thu, 8 Oct 2026 22:22:23 -0700 Subject: [PATCH 6/8] chore(dead-exports): allowlist cl-9807-extract-agent-shakespeare package public surface --- scripts/dead-export-allowlist.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/dead-export-allowlist.txt b/scripts/dead-export-allowlist.txt index 2769cf3a3..bf9856198 100644 --- a/scripts/dead-export-allowlist.txt +++ b/scripts/dead-export-allowlist.txt @@ -61,3 +61,7 @@ agents/artist/src/index.ts: agent agents/artist/src/index.ts: defineAgent agents/artist/src/config.ts: satisfies agents/artist/src/config.ts: boolean +agents/shakespeare/src/index.ts: agent +agents/shakespeare/src/index.ts: defineAgent +agents/shakespeare/src/config.ts: satisfies +agents/shakespeare/src/config.ts: boolean From 372a024a0e8be30a539cdcd037327a42d175ea8d Mon Sep 17 00:00:00 2001 From: "user.email" Date: Thu, 8 Oct 2026 22:29:50 -0700 Subject: [PATCH 7/8] style(agent-shakespeare): restore trailing newlines in package sources oxfmt requires a trailing newline; the de-slop edit stripped it from five source files, failing the static-analysis oxfmt step. --- agents/shakespeare/src/agent.ts | 2 +- agents/shakespeare/src/config.ts | 2 +- agents/shakespeare/src/director.ts | 2 +- agents/shakespeare/src/index.ts | 2 +- agents/shakespeare/src/toolset.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/agents/shakespeare/src/agent.ts b/agents/shakespeare/src/agent.ts index 590d28f54..f91f54153 100644 --- a/agents/shakespeare/src/agent.ts +++ b/agents/shakespeare/src/agent.ts @@ -17,4 +17,4 @@ export function defineAgent(): AgentDefinition { }, tags: { fleet: "0.3.36", lane: "shakespeare" }, }); -} \ No newline at end of file +} diff --git a/agents/shakespeare/src/config.ts b/agents/shakespeare/src/config.ts index b6bd09a7b..385c48cb8 100644 --- a/agents/shakespeare/src/config.ts +++ b/agents/shakespeare/src/config.ts @@ -6,4 +6,4 @@ export const config = { spawn: { maySpawn: boolean }; tier: string; modelRole: string; -}; \ No newline at end of file +}; diff --git a/agents/shakespeare/src/director.ts b/agents/shakespeare/src/director.ts index e90a1d4cc..f65818174 100644 --- a/agents/shakespeare/src/director.ts +++ b/agents/shakespeare/src/director.ts @@ -17,4 +17,4 @@ export const director = { spawn: config.spawn, tier: config.tier, modelRole: config.modelRole, -} as const; \ No newline at end of file +} as const; diff --git a/agents/shakespeare/src/index.ts b/agents/shakespeare/src/index.ts index e87040867..c2c15f6c6 100644 --- a/agents/shakespeare/src/index.ts +++ b/agents/shakespeare/src/index.ts @@ -2,4 +2,4 @@ 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"; \ No newline at end of file +export { config } from "./config.js"; diff --git a/agents/shakespeare/src/toolset.ts b/agents/shakespeare/src/toolset.ts index b954e1031..f0bc785e8 100644 --- a/agents/shakespeare/src/toolset.ts +++ b/agents/shakespeare/src/toolset.ts @@ -13,4 +13,4 @@ const SHAKESPEARE_TOOLS = [ "delete_file", ] as const; -export const tools: readonly string[] = [...SHAKESPEARE_TOOLS]; \ No newline at end of file +export const tools: readonly string[] = [...SHAKESPEARE_TOOLS]; From c0ec7fab6070ee7d90cfdbf699868bff035277af Mon Sep 17 00:00:00 2001 From: "user.email" Date: Thu, 8 Oct 2026 23:52:53 -0700 Subject: [PATCH 8/8] fix(agent-shakespeare): drop hardcoded inference source and release tag --- agents/shakespeare/src/agent.ts | 5 +---- agents/shakespeare/src/toolset.ts | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/agents/shakespeare/src/agent.ts b/agents/shakespeare/src/agent.ts index f91f54153..6cfe96ffd 100644 --- a/agents/shakespeare/src/agent.ts +++ b/agents/shakespeare/src/agent.ts @@ -12,9 +12,6 @@ export function defineAgent(): AgentDefinition { systemPrompt: systemPrompt.build(), tools: [], capabilities: [], - inference: { - sources: [{ provider: "openai", model: "gpt-5" }], - }, - tags: { fleet: "0.3.36", lane: "shakespeare" }, + inference: { sources: [] }, }); } diff --git a/agents/shakespeare/src/toolset.ts b/agents/shakespeare/src/toolset.ts index f0bc785e8..f221dbaf9 100644 --- a/agents/shakespeare/src/toolset.ts +++ b/agents/shakespeare/src/toolset.ts @@ -1,4 +1,4 @@ -const SHAKESPEARE_TOOLS = [ +export const tools: readonly string[] = [ "read_file", "grep", "search_files", @@ -12,5 +12,3 @@ const SHAKESPEARE_TOOLS = [ "edit_file", "delete_file", ] as const; - -export const tools: readonly string[] = [...SHAKESPEARE_TOOLS];