From f173b7e81b120ca48625e6f5b1e4cb26ab25acb9 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sat, 12 Sep 2026 09:48:29 -0700 Subject: [PATCH 1/3] Revert "Restore Gaasbot CTO voice from the GaaS original, keep it off (#932)" This reverts commit dcd1a8ec13d11c0bc70374b270d865aeb8536a7b. --- src/agent/directors/gaasbot/package.test.ts | 26 +-------------------- src/agent/directors/gaasbot/package.ts | 16 +------------ 2 files changed, 2 insertions(+), 40 deletions(-) diff --git a/src/agent/directors/gaasbot/package.test.ts b/src/agent/directors/gaasbot/package.test.ts index 2d99a02ee..df5a018e3 100644 --- a/src/agent/directors/gaasbot/package.test.ts +++ b/src/agent/directors/gaasbot/package.test.ts @@ -79,37 +79,13 @@ describe("gaasbotPackage", () => { expect(gaasbotPackage.modelRole).toBe("plan"); }); - test("optionalSkills is style, philosophy, and native-integration", () => { + test("optionalSkills is philosophy and native-integration", () => { expect(gaasbotPackage.optionalSkills).toEqual([ - "style", "philosophy", "native-integration", ]); }); - test("systemPrompt carries the CTO voice strands (contract, not phrasing)", () => { - const p = gaasbotPackage.systemPrompt; - expect(p).toMatch(/squash PR commits/i); - expect(p).toMatch(/hooks must be on/i); - expect(p).toMatch(/loose coupling|composability/i); - expect(p).toMatch(/owns the constraint|owning layer/i); - expect(p).toMatch(/statically-typed|static types/i); - expect(p).toMatch(/Push back when/i); - expect(p).toMatch(/Stay flexible when/i); - expect(p).toMatch(/symptom-chasing/i); - expect(p).toMatch(/parent\/operator/i); - }); - - test("CTO voice grants no ship/implement/merge-block/spawn powers", () => { - const p = gaasbotPackage.systemPrompt; - expect(p).not.toMatch( - /you (may|can|will|should) (ship|implement|merge|spawn|block)/i, - ); - expect(p).not.toMatch(/go ahead and (ship|implement|merge)/i); - expect(p).not.toMatch(/merge-block(ing|er)? (powers|authority)/i); - expect(p).not.toMatch(/act as (a|the) (gate|implementer|orchestrator)/i); - }); - test("primaryIntent and outOfLane match risk counsel lane", () => { expect(gaasbotPackage.primaryIntent).toMatch(/[Rr]isk counsel/i); expect(gaasbotPackage.description).toMatch(/[Rr]isk counsel/i); diff --git a/src/agent/directors/gaasbot/package.ts b/src/agent/directors/gaasbot/package.ts index ba822fa9e..3141e6e2d 100644 --- a/src/agent/directors/gaasbot/package.ts +++ b/src/agent/directors/gaasbot/package.ts @@ -4,8 +4,6 @@ import { REVIEW_TOOLS } from "../tool-sets.js"; /** * Risk counsel worker (CL-7028). Package id/path remains `gaasbot`. * Strategic risk/sequencing advice — not a hard gate, not implement, not Greybeard/Counsel. - * CTO voice ported from abklabs/agents plugins/gaas/agents/gaasbot.md @ 6e16b6c - * (6e16b6c not resolvable locally; ported from the local HEAD copy instead). */ export const gaasbotPackage: DirectorPackage = { id: "gaasbot", @@ -18,7 +16,7 @@ export const gaasbotPackage: DirectorPackage = { "applying product fixes", ], description: "Risk counsel — strategic ship/sequencing advice, not a gate", - optionalSkills: ["style", "philosophy", "native-integration"], + optionalSkills: ["philosophy", "native-integration"], tools: { allow: REVIEW_TOOLS }, spawn: { maySpawn: false }, tier: "leaf", @@ -40,17 +38,5 @@ DONE GATE: Stop when the brief's risk/sequencing ask is answered OR Blockers are OUT OF LANE: shipping product code, architecture gate ownership (Greybeard), eng plan authorship (Counsel), merge-block theater without evidence, becoming Builder/Critic/orchestrator as primary. -CTO VOICE (ported from the GaaS original): direct, conversational, professional without stuffy. Plain language, occasionally colorful. No padding, no hedged softeners — when something is wrong, say so and move on. "user" means the parent/operator. No emojis. - -Git discipline: squash PR commits before merging. Git hooks must be on — a commit that bypasses checks means the setup is broken. Run the repo check gate before opening a PR. - -Architecture opinions: composability and loose coupling — interfaces over implementations, plugins over monoliths. Move logic to the layer that owns the constraint instead of working around it downstream. Expose hooks and plugin points rather than bespoke forks per use case. Start with the greatest hits — ship the common cases, expand deliberately. Flag experimental work behind flags. Accept old shapes without over-engineering backwards compatibility; duplicate a type rather than couple packages through types. - -Tech preferences (pragmatic, maintained, out of the way — new tools only when they solve a real problem): strict static types that catch bugs at compile time; explicit inspectable builds; broad-compatibility open-source licenses; modern runtimes without polyfill or transpilation layers. - -Push back when: complexity is proposed for a hypothetical future; type assertions stand in for validation; state lives where it does not belong; layers pile up without owning a constraint. Stay flexible when: the current code is a known hack; an external contributor has a legitimate use case (offer a fitting alternative, do not just close the door); shipped beats perfect — documented temporary workarounds are fine; docs pseudo-code does not need to compile. - -How to respond: be direct and specific — what to change and why, with codebase references and a concrete alternative. Reason architecture from the principles above; weigh prioritization against business impact and simplicity. Say "I don't know" over feigning certainty. Call out symptom-chasing and redirect to the owning layer. - Findings: risk and sequencing advice — blockers, ship-with-note, filed-for-later, and the unraised miss.`, }; From 509c1d290894981484c91cfe98253c41d0e3f5c5 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sat, 12 Sep 2026 09:48:30 -0700 Subject: [PATCH 2/3] Revert "Restore Greybeard review checklist in Corbits idiom (#944)" This reverts commit 2291dca7544148c5a1341d73e876fe4c26543dbf. --- src/agent/directors/greybeard/package.test.ts | 46 ++----------------- src/agent/directors/greybeard/package.ts | 14 ++---- 2 files changed, 6 insertions(+), 54 deletions(-) diff --git a/src/agent/directors/greybeard/package.test.ts b/src/agent/directors/greybeard/package.test.ts index 73ed1da07..05eb7fd56 100644 --- a/src/agent/directors/greybeard/package.test.ts +++ b/src/agent/directors/greybeard/package.test.ts @@ -22,52 +22,12 @@ describe("greybeardPackage", () => { expect(p).not.toMatch(/architecture director/i); }); - test("systemPrompt frames value as analysis via Corbits read tools", () => { + test("systemPrompt teaches judgment for architecture approach", () => { const p = greybeardPackage.systemPrompt; - expect(p).toMatch(/value is analysis/i); - expect(p).toContain("read_file"); - expect(p).toContain("grep"); - expect(p).toContain("ask_director"); - }); - - test("systemPrompt carries an ordered review checklist", () => { - const p = greybeardPackage.systemPrompt; - expect(p).toMatch(/Review checklist/); - expect(p).toMatch(/architectural claim/); + expect(p).toContain("Judge the approach"); expect(p).toMatch(/constraint ownership|owns constraints/i); - expect(p).toMatch(/anti-patterns/); - expect(p).toMatch(/Rank risks/); - const checklistIdx = p.search(/Review checklist/); - expect(checklistIdx).toBeGreaterThan(-1); - const checklist = p.slice(checklistIdx); - const claimIdx = checklist.search(/architectural claim/); - const ownershipIdx = checklist.search(/constraint ownership|owns constraints/i); - const holesIdx = checklist.search(/anti-patterns/); - const risksIdx = checklist.search(/Rank risks/); - const verdictIdx = checklist.search(/hold \/ revise \/ block/); - expect(claimIdx).toBeGreaterThan(-1); - expect(ownershipIdx).toBeGreaterThan(claimIdx); - expect(holesIdx).toBeGreaterThan(ownershipIdx); - expect(risksIdx).toBeGreaterThan(holesIdx); - expect(verdictIdx).toBeGreaterThan(risksIdx); - }); - - test("systemPrompt ends the checklist with the hold/revise/block verdict triad", () => { - const p = greybeardPackage.systemPrompt; - expect(p).toMatch(/hold \/ revise \/ block/); + expect(p).toMatch(/hold \/ revise \/ block|verdict/i); expect(p).toMatch(/backward-compatibility|backward compatibility/i); - const risksIdx = p.search(/Rank risks/); - const triadIdx = p.search(/hold \/ revise \/ block/); - expect(risksIdx).toBeGreaterThan(-1); - expect(triadIdx).toBeGreaterThan(risksIdx); - }); - - test("systemPrompt has no self-spawn language", () => { - const p = greybeardPackage.systemPrompt; - expect(p).not.toMatch(/spawn.*greybeard/i); - expect(p).not.toContain('agent="greybeard"'); - expect(p).not.toMatch(/spawn yourself/i); - expect(p).not.toMatch(/spawn a (greybeard|reviewer)/i); }); test("systemPrompt allows limited spawn without fake caps or scheduler language", () => { diff --git a/src/agent/directors/greybeard/package.ts b/src/agent/directors/greybeard/package.ts index 9fab55ab7..a9cac2438 100644 --- a/src/agent/directors/greybeard/package.ts +++ b/src/agent/directors/greybeard/package.ts @@ -3,11 +3,7 @@ import { ORCHESTRATOR_TOOLS } from "../tool-sets.js"; /** * Greybeard nested orchestrator (CL-7019). - * Review checklist ported from the GaaS greybeard original (CL-7662) — the - * GaaS source was unavailable locally, so this is a Corbits-idiom restoration - * rather than a 1:1 copy. Self-read deviation: the GaaS delegate-for-review - * shape becomes read_file/grep/ask_director first, spawn only on a concrete - * unknown. Architecture judgment with limited spawn — never ships product code. + * Architecture judgment with limited spawn — never ships product code. */ export const greybeardPackage: DirectorPackage = { id: "greybeard", @@ -30,16 +26,12 @@ You are Greybeard — not a second Skywalker, not Critic (code defects with evid Follow style and philosophy conventions (baked into this prompt) when reviewing plans or approaches — skills are active constraints, not background docs. -Your value is analysis, not delegation: reach the judgment yourself with -targeted reads (read_file, grep) and pointed questions (ask_director) -before considering a spawn. - -Review checklist — work the list in order: +Judge the approach: 1. Name the architectural claim under review (boundary, ownership, invariant, or BC surface). 2. Decide whether the proposed approach owns constraints at the right layer — or only chases symptoms. 3. Call out holes, anti-patterns, missing invariants, product/architecture/implementation misalignment, and duplication that should be refactor or API expansion instead. 4. Rank risks for long-term maintainability and backward compatibility. -5. Report a clear verdict: hold / revise / block — with the why, not checklist theater. +5. Report a clear verdict: hold / revise / block — with the why, not a checklist theater. Spawn only when a concrete unknown blocks that judgment. Package spawn rules allow intern (mechanical shell), explorer (map/read), and critic (code evidence). When spawning critic, pass non-empty success_criteria (runtime fail-closes without it). intern and explorer remain optional. Prefer doing the review yourself with mounted read/search tools. Do not invent numeric spawn caps or act as a scheduler — width follows the unknown, not a soft ladder. Spawn then idle; reports arrive as mailbox mail — do not poll. From 94aebf3dea85f05d09404fdc26fd5570dd9409e4 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sat, 12 Sep 2026 09:48:31 -0700 Subject: [PATCH 3/3] Revert "Warn when an agent plugin prompt file is missing (#928)" This reverts commit 9ff51db63cf73c57ae97d6516697b6d5cd253c4c. --- src/plugins/agent-plugins.test.ts | 18 ------------------ src/plugins/agent-plugins.ts | 16 ++++++---------- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/src/plugins/agent-plugins.test.ts b/src/plugins/agent-plugins.test.ts index 6266b0b97..8533cd0eb 100644 --- a/src/plugins/agent-plugins.test.ts +++ b/src/plugins/agent-plugins.test.ts @@ -176,22 +176,4 @@ describe("resolveAgentPluginProfiles", () => { ), ).toBe(true); }); - - test("warns once when a prompt file is missing and still loads the profile", async () => { - const { mod, config } = agentModule("p1", [ - { id: "scout", systemPromptPath: "prompts/does-not-exist.md" }, - ]); - mod.dir = "/tmp/wt-cl-6724-missing-prompt-dir"; - const warnings: string[] = []; - const profiles = await resolveAgentPluginProfiles([mod], config, (msg) => - warnings.push(msg), - ); - expect(profiles.length).toBe(1); - expect(defined(profiles[0]).systemPromptRole).toBeUndefined(); - expect(warnings.length).toBe(1); - expect(warnings[0]).toContain('"p1"'); - expect(warnings[0]).toContain('"scout"'); - expect(warnings[0]).toContain("prompts/does-not-exist.md"); - expect(defined(warnings[0])).toMatch(/unreadable|missing/i); - }); }); diff --git a/src/plugins/agent-plugins.ts b/src/plugins/agent-plugins.ts index cc912fa75..f8bb37c36 100644 --- a/src/plugins/agent-plugins.ts +++ b/src/plugins/agent-plugins.ts @@ -90,18 +90,14 @@ export async function resolveAgentPluginProfiles( profile.systemPromptRole === undefined && mod.dir !== undefined ) { - const promptPath = join(mod.dir, profile.systemPromptPath); try { - const promptRaw = await readFile(promptPath, "utf8"); - profile.systemPromptRole = promptRaw.trim(); - } catch (err) { - const reason = - (err instanceof Error ? err.message : String(err)) - .split("\n")[0] - ?.trim() || "unknown error"; - onWarning( - `plugin "${mod.manifest.id}" agent "${profile.id}" systemPromptPath "${profile.systemPromptPath}" unreadable (${promptPath}): ${reason}`, + const promptRaw = await readFile( + join(mod.dir, profile.systemPromptPath), + "utf8", ); + profile.systemPromptRole = promptRaw.trim(); + } catch { + // Missing prompt file is non-fatal — the profile loads without a role. } } // Provenance for search_agents: Claude marketplace installs stamp