From 14fc87f2494900509953c7ac8153e1dcb35bdfc2 Mon Sep 17 00:00:00 2001 From: Sawyer Date: Sun, 4 Oct 2026 23:49:08 -0700 Subject: [PATCH 1/9] feat(prober): ship prober as a workspace agent package --- agents/prober/package.json | 13 +++++ .../package.ts => agents/prober/src/index.ts | 47 +++++++++++++++++-- bun.lock | 6 +++ package.json | 1 + src/agent/directors/prober/package.test.ts | 25 ++++++++++ src/agent/directors/registry.ts | 2 +- tsconfig.json | 1 + 7 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 agents/prober/package.json rename src/agent/directors/prober/package.ts => agents/prober/src/index.ts (76%) create mode 100644 src/agent/directors/prober/package.test.ts diff --git a/agents/prober/package.json b/agents/prober/package.json new file mode 100644 index 000000000..18c641dff --- /dev/null +++ b/agents/prober/package.json @@ -0,0 +1,13 @@ +{ + "name": "@corbits/agent-prober", + "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/prober/package.ts b/agents/prober/src/index.ts similarity index 76% rename from src/agent/directors/prober/package.ts rename to agents/prober/src/index.ts index d089ffe3d..9173a9ee4 100644 --- a/src/agent/directors/prober/package.ts +++ b/agents/prober/src/index.ts @@ -1,12 +1,49 @@ -import type { DirectorPackage } from "../types.js"; -import { REVIEW_TOOLS } from "../tool-sets.js"; - /** * Prober worker (CL-7656). * Measure-only latency/behavior prober — report distributions per * family/model; never ship product code, never tune prompts or policy. + * + * Ships as the @corbits/agent-prober 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/prober/package.test.ts. */ -export const proberPackage: DirectorPackage = { +export type AgentPackage = { + readonly id: "prober"; + readonly primaryIntent: string; + readonly outOfLane: readonly string[]; + readonly description: string; + readonly systemPrompt: string; + /** Unset — prober never attaches skill bodies at spawn. */ + readonly attachedSkills?: readonly string[]; + /** Unset — prober declares no skill scope. */ + readonly optionalSkills?: readonly string[]; + readonly tools: { + readonly allow: readonly string[]; + }; + readonly spawn: { + readonly maySpawn: false; + }; + readonly modelRole: "test"; + readonly tier: "leaf"; +}; + +const PROBER_TOOLS = [ + "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; + +export const proberPackage: AgentPackage = { id: "prober", primaryIntent: "Measure latency and behavior distributions per family/model; never ship product code, never tune prompts or policy", @@ -68,7 +105,7 @@ retunes, or orchestration. OUT OF LANE: shipping product code, tuning prompts or model-family policy (route to follow-up tickets), building a new harness, fleet orchestration, architecture essays without measurements.`, - tools: { allow: REVIEW_TOOLS }, + tools: { allow: [...PROBER_TOOLS] }, spawn: { maySpawn: false }, tier: "leaf", modelRole: "test", diff --git a/bun.lock b/bun.lock index 71a4669c4..22b491aa0 100644 --- a/bun.lock +++ b/bun.lock @@ -5,6 +5,7 @@ "": { "name": "@corbits/code", "dependencies": { + "@corbits/agent-prober": "workspace:*", "@corbits/codex-provider": "0.1.1", "@corbits/oauth-core": "0.2.0", "@corbits/openai-responses": "0.2.1", @@ -53,8 +54,12 @@ "agents/artist": { "name": "@corbits/code-agent-artist", }, +<<<<<<< HEAD "agents/shakespeare": { "name": "@corbits/code-agent-shakespeare", + }, + "agents/prober": { + "name": "@corbits/agent-prober", "version": "0.1.0", }, "packages/first-class-providers": { @@ -250,6 +255,7 @@ "@corbits/code-agent-artist": ["@corbits/code-agent-artist@workspace:agents/artist"], "@corbits/code-agent-shakespeare": ["@corbits/code-agent-shakespeare@workspace:agents/shakespeare"], + "@corbits/agent-prober": ["@corbits/agent-prober@workspace:agents/prober"], "@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..92d68db2c 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "tar": "^7.5.1" }, "dependencies": { + "@corbits/agent-prober": "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/prober/package.test.ts b/src/agent/directors/prober/package.test.ts new file mode 100644 index 000000000..871273bf4 --- /dev/null +++ b/src/agent/directors/prober/package.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, test } from "bun:test"; + +import { proberPackage } from "@corbits/agent-prober"; +import { REVIEW_TOOLS } from "../tool-sets.js"; +import { DIRECTOR_REGISTRY } from "../registry.js"; +import type { DirectorPackage } from "../types.js"; + +describe("proberPackage", () => { + test("workspace package satisfies the director contract and feeds the registry", () => { + const asDirector: DirectorPackage = proberPackage; + expect(asDirector.id).toBe("prober"); + expect(DIRECTOR_REGISTRY.prober).toBe(proberPackage); + expect([...proberPackage.tools.allow]).toEqual([...REVIEW_TOOLS]); + }); + + test("extracted copy stays measure-only and non-spawning", () => { + expect(proberPackage.tools.allow).toContain("read_file"); + expect(proberPackage.tools.allow).toContain("grep"); + expect(proberPackage.tools.allow).not.toContain("spawn_agent"); + expect(proberPackage.tools.allow).not.toContain("ask_operator"); + expect(proberPackage.spawn.maySpawn).toBe(false); + expect(proberPackage.tier).toBe("leaf"); + expect(proberPackage.modelRole).toBe("test"); + }); +}); diff --git a/src/agent/directors/registry.ts b/src/agent/directors/registry.ts index 2c5ed6b65..8ae6c4e77 100644 --- a/src/agent/directors/registry.ts +++ b/src/agent/directors/registry.ts @@ -1,4 +1,5 @@ import { director as shakespeareDirector } from "@corbits/code-agent-shakespeare"; +import { proberPackage } from "@corbits/agent-prober"; import type { AgentProfile, CapabilityFilter } from "../profile-types.js"; import { director as artistDirector } from "@corbits/code-agent-artist"; import { coderPackage } from "./coder/package.js"; @@ -6,7 +7,6 @@ import { designerPackage } from "./designer/package.js"; import { dispatchPackage } from "./dispatch/package.js"; import { explorerPackage } from "./explorer/package.js"; 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 { wardenPackage } from "./warden/package.js"; diff --git a/tsconfig.json b/tsconfig.json index df0b1cca4..da36eb052 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,7 @@ "paths": { "@corbits/code-agent-artist": ["./agents/artist/src/index.ts"], "@corbits/code-agent-shakespeare": ["./agents/shakespeare/src/index.ts"], + "@corbits/agent-prober": ["./agents/prober/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 e72e6f7ea36f864d3c980e9495bfec9880422361 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Thu, 8 Oct 2026 14:00:49 -0700 Subject: [PATCH 2/9] chore(prober): rename package to @corbits/code-agent-prober --- agents/prober/package.json | 2 +- agents/prober/src/index.ts | 2 +- bun.lock | 7 +++---- package.json | 2 +- src/agent/directors/prober/package.test.ts | 2 +- src/agent/directors/registry.ts | 2 +- tsconfig.json | 2 +- 7 files changed, 9 insertions(+), 10 deletions(-) diff --git a/agents/prober/package.json b/agents/prober/package.json index 18c641dff..0db73dbf1 100644 --- a/agents/prober/package.json +++ b/agents/prober/package.json @@ -1,5 +1,5 @@ { - "name": "@corbits/agent-prober", + "name": "@corbits/code-agent-prober", "version": "0.1.0", "private": true, "type": "module", diff --git a/agents/prober/src/index.ts b/agents/prober/src/index.ts index 9173a9ee4..2fc7f98cb 100644 --- a/agents/prober/src/index.ts +++ b/agents/prober/src/index.ts @@ -3,7 +3,7 @@ * Measure-only latency/behavior prober — report distributions per * family/model; never ship product code, never tune prompts or policy. * - * Ships as the @corbits/agent-prober workspace package: the tool allowlist + * Ships as the @corbits/code-agent-prober 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/prober/package.test.ts. */ diff --git a/bun.lock b/bun.lock index 22b491aa0..9def48215 100644 --- a/bun.lock +++ b/bun.lock @@ -5,7 +5,7 @@ "": { "name": "@corbits/code", "dependencies": { - "@corbits/agent-prober": "workspace:*", + "@corbits/code-agent-prober": "workspace:*", "@corbits/codex-provider": "0.1.1", "@corbits/oauth-core": "0.2.0", "@corbits/openai-responses": "0.2.1", @@ -54,12 +54,11 @@ "agents/artist": { "name": "@corbits/code-agent-artist", }, -<<<<<<< HEAD "agents/shakespeare": { "name": "@corbits/code-agent-shakespeare", }, "agents/prober": { - "name": "@corbits/agent-prober", + "name": "@corbits/code-agent-prober", "version": "0.1.0", }, "packages/first-class-providers": { @@ -255,7 +254,7 @@ "@corbits/code-agent-artist": ["@corbits/code-agent-artist@workspace:agents/artist"], "@corbits/code-agent-shakespeare": ["@corbits/code-agent-shakespeare@workspace:agents/shakespeare"], - "@corbits/agent-prober": ["@corbits/agent-prober@workspace:agents/prober"], + "@corbits/code-agent-prober": ["@corbits/code-agent-prober@workspace:agents/prober"], "@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 92d68db2c..186d93658 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "tar": "^7.5.1" }, "dependencies": { - "@corbits/agent-prober": "workspace:*", + "@corbits/code-agent-prober": "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/prober/package.test.ts b/src/agent/directors/prober/package.test.ts index 871273bf4..03442ed07 100644 --- a/src/agent/directors/prober/package.test.ts +++ b/src/agent/directors/prober/package.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test"; -import { proberPackage } from "@corbits/agent-prober"; +import { proberPackage } from "@corbits/code-agent-prober"; import { REVIEW_TOOLS } from "../tool-sets.js"; import { DIRECTOR_REGISTRY } from "../registry.js"; import type { DirectorPackage } from "../types.js"; diff --git a/src/agent/directors/registry.ts b/src/agent/directors/registry.ts index 8ae6c4e77..8f2fe33ba 100644 --- a/src/agent/directors/registry.ts +++ b/src/agent/directors/registry.ts @@ -1,5 +1,5 @@ import { director as shakespeareDirector } from "@corbits/code-agent-shakespeare"; -import { proberPackage } from "@corbits/agent-prober"; +import { proberPackage } from "@corbits/code-agent-prober"; 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/tsconfig.json b/tsconfig.json index da36eb052..c7e3946b1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,7 @@ "paths": { "@corbits/code-agent-artist": ["./agents/artist/src/index.ts"], "@corbits/code-agent-shakespeare": ["./agents/shakespeare/src/index.ts"], - "@corbits/agent-prober": ["./agents/prober/src/index.ts"], + "@corbits/code-agent-prober": ["./agents/prober/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 f9f05a063c4f45405b263b093aa2f416991d6e1c Mon Sep 17 00:00:00 2001 From: Sawyer Date: Thu, 8 Oct 2026 19:45:31 -0700 Subject: [PATCH 3/9] feat(agent-prober): adopt uniform reusable agent template shape --- agents/prober/README.md | 35 ++++++ agents/prober/src/agent.ts | 24 +++++ agents/prober/src/config.ts | 13 +++ agents/prober/src/director.ts | 26 +++++ agents/prober/src/index.ts | 120 ++------------------- agents/prober/src/prompt.ts | 62 +++++++++++ agents/prober/src/toolset.ts | 20 ++++ agents/prober/tsconfig.json | 7 ++ bun.lock | 1 - package.json | 1 - src/agent/directors/prober/package.test.ts | 46 +++++--- src/agent/directors/registry.ts | 4 +- 12 files changed, 231 insertions(+), 128 deletions(-) create mode 100644 agents/prober/README.md create mode 100644 agents/prober/src/agent.ts create mode 100644 agents/prober/src/config.ts create mode 100644 agents/prober/src/director.ts create mode 100644 agents/prober/src/prompt.ts create mode 100644 agents/prober/src/toolset.ts create mode 100644 agents/prober/tsconfig.json diff --git a/agents/prober/README.md b/agents/prober/README.md new file mode 100644 index 000000000..84eee3bdc --- /dev/null +++ b/agents/prober/README.md @@ -0,0 +1,35 @@ +# @corbits/code-agent-prober + +## What this is + +Ready `@corbits/code-agent-prober` agent + independently importable components: +`agent`, `defineAgent`, `director`, `tools`, `systemPrompt`, `config`. + +## Consume (runLocal) + +```ts +import { agent } from "@corbits/code-agent-prober"; +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-prober"; +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/prober/package.test.ts`. diff --git a/agents/prober/src/agent.ts b/agents/prober/src/agent.ts new file mode 100644 index 000000000..b9010306c --- /dev/null +++ b/agents/prober/src/agent.ts @@ -0,0 +1,24 @@ +import { + defineAgent as coreDefineAgent, + type AgentDefinition, +} from "@intx/agent"; +import { systemPrompt } from "./prompt.js"; + +/** + * Prober 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: "prober", + 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: "prober" }, + }); +} diff --git a/agents/prober/src/config.ts b/agents/prober/src/config.ts new file mode 100644 index 000000000..4132c6b33 --- /dev/null +++ b/agents/prober/src/config.ts @@ -0,0 +1,13 @@ +/** Prober worker — measure-only latency/behavior prober per family/model. */ +export const config = { + spawn: { maySpawn: false }, + tier: "leaf", + // Preserved from the original in-tree card (behavior wins over the contract + // §5 map; test defaults to medium effort in identity.ts, matching the + // measure-only lane). + modelRole: "test", +} as const satisfies { + spawn: { maySpawn: boolean }; + tier: string; + modelRole: string; +}; diff --git a/agents/prober/src/director.ts b/agents/prober/src/director.ts new file mode 100644 index 000000000..cccb26f92 --- /dev/null +++ b/agents/prober/src/director.ts @@ -0,0 +1,26 @@ +import { tools } from "./toolset.js"; +import { systemPrompt } from "./prompt.js"; +import { config } from "./config.js"; + +/** + * Prober worker director card (CL-7656). Structurally satisfies the app's + * `DirectorPackage` (app-side drift-guard asserts assignability). App-independent. + */ +export const director = { + id: "prober", + primaryIntent: + "Measure latency and behavior distributions per family/model; never ship product code, never tune prompts or policy", + outOfLane: [ + "shipping product code", + "tuning prompts or model-family policy", + "building a new eval harness", + "fleet orchestration", + "architecture essays without measurements", + ], + description: "Measure-only latency/behavior prober per family/model", + systemPrompt: systemPrompt.build(), + tools: { allow: [...tools] }, + spawn: config.spawn, + tier: config.tier, + modelRole: config.modelRole, +} as const; diff --git a/agents/prober/src/index.ts b/agents/prober/src/index.ts index 2fc7f98cb..95fc4d646 100644 --- a/agents/prober/src/index.ts +++ b/agents/prober/src/index.ts @@ -1,112 +1,8 @@ -/** - * Prober worker (CL-7656). - * Measure-only latency/behavior prober — report distributions per - * family/model; never ship product code, never tune prompts or policy. - * - * Ships as the @corbits/code-agent-prober 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/prober/package.test.ts. - */ -export type AgentPackage = { - readonly id: "prober"; - readonly primaryIntent: string; - readonly outOfLane: readonly string[]; - readonly description: string; - readonly systemPrompt: string; - /** Unset — prober never attaches skill bodies at spawn. */ - readonly attachedSkills?: readonly string[]; - /** Unset — prober declares no skill scope. */ - readonly optionalSkills?: readonly string[]; - readonly tools: { - readonly allow: readonly string[]; - }; - readonly spawn: { - readonly maySpawn: false; - }; - readonly modelRole: "test"; - readonly tier: "leaf"; -}; - -const PROBER_TOOLS = [ - "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; - -export const proberPackage: AgentPackage = { - id: "prober", - primaryIntent: - "Measure latency and behavior distributions per family/model; never ship product code, never tune prompts or policy", - outOfLane: [ - "shipping product code", - "tuning prompts or model-family policy", - "building a new eval harness", - "fleet orchestration", - "architecture essays without measurements", - ], - description: "Measure-only latency/behavior prober per family/model", - systemPrompt: `You are ProberDirector (Prober), a specialist in Corbits Code. - -PRIMARY INTENT: measure latency and behavior distributions per family/model and report the numbers with evidence. Never ship product code. Never tune prompts or model-family policy. Findings feed model-family-policy as follow-up tickets — never silent retunes. - -You are the measure-only lane — not Coder, not Planner, not an orchestrator. Do not spawn specialists. Do not edit product code, prompts, or policy to "improve" the numbers mid-probe; a probe that moves the target is not a measurement. - -BLINDERS ON: measure what the brief's success_criteria ask for, on the harness below, sliced per family/model. Do not wander into fixes, retunes, or fleet orchestration. - -# What to measure - -- TTFT (time to first token) and per-turn latency distributions. -- Tool-only streak distribution (consecutive tool-call turns with no text). -- Salvage counts (incomplete-report recoveries) and nudge counts - (wrap-up / stall check-ins) per family/model. -- Always slice by family/model — a global average that hides a family - regression is a failed probe. - -# Harness (consume — do not build a second one) - -- Capability runs: \`bun run eval:capability\` (\`scripts/eval-capability.ts\` - over \`evals/capability\`) — the product non-TUI path (\`loadConfig\` + - \`runExec\`) against fixture copies with \`verify.sh\` graders. -- Latency spans: the PerfTrace harness under \`src/perf\` — \`rollup.ts\` - (TTFT vs stream split), \`assert-spans.ts\` (span assertions), and - \`attribution-report.ts\` (per-turn attribution). -- Read how they invoke before running; extend neither. If the harness - cannot answer the brief, report that under Blockers — do not hand-roll - a replacement harness. - -# Findings route to follow-ups, never silent retunes - -- Report numbers with the exact commands, matrix cells, and harness - outputs behind them so a follow-up can reproduce the probe. -- Policy-looking conclusions (e.g. "family X needs a tighter tool-only - nudge") go to Blockers/Findings as follow-up tickets against - \`src/agent/model-family-policy.ts\` — do not edit the policy here. -- Prompt-looking conclusions go the same route — named follow-ups, not - edits. - -# Report - -When done, stop tooling and reply with ONLY the Corbits report envelope — the shared scaffold owns its shape (Summary / Findings / Blockers / Paths, in that order), so this package does not re-specify it. Findings for this lane: distributions per family/model (TTFT, per-turn latency, tool-only streaks, salvage/nudge counts), the exact harness commands and matrix behind them, and follow-up tickets for policy/prompt owners. - -DONE GATE: stop when the brief's measure ask is answered with evidence -OR explicitly blocked under Blockers. Do not expand into fixes, -retunes, or orchestration. - -OUT OF LANE: shipping product code, tuning prompts or model-family -policy (route to follow-up tickets), building a new harness, fleet -orchestration, architecture essays without measurements.`, - tools: { allow: [...PROBER_TOOLS] }, - spawn: { maySpawn: false }, - tier: "leaf", - modelRole: "test", -}; +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/prober/src/prompt.ts b/agents/prober/src/prompt.ts new file mode 100644 index 000000000..a676be20e --- /dev/null +++ b/agents/prober/src/prompt.ts @@ -0,0 +1,62 @@ +// Prober raw director card (CL-7656). Byte-stable, single authority — the +// app formats the identity header via formatDirectorSystemPrompt. + +const CARD = `You are ProberDirector (Prober), a specialist in Corbits Code. + +PRIMARY INTENT: measure latency and behavior distributions per family/model and report the numbers with evidence. Never ship product code. Never tune prompts or model-family policy. Findings feed model-family-policy as follow-up tickets — never silent retunes. + +You are the measure-only lane — not Coder, not Planner, not an orchestrator. Do not spawn specialists. Do not edit product code, prompts, or policy to "improve" the numbers mid-probe; a probe that moves the target is not a measurement. + +BLINDERS ON: measure what the brief's success_criteria ask for, on the harness below, sliced per family/model. Do not wander into fixes, retunes, or fleet orchestration. + +# What to measure + +- TTFT (time to first token) and per-turn latency distributions. +- Tool-only streak distribution (consecutive tool-call turns with no text). +- Salvage counts (incomplete-report recoveries) and nudge counts + (wrap-up / stall check-ins) per family/model. +- Always slice by family/model — a global average that hides a family + regression is a failed probe. + +# Harness (consume — do not build a second one) + +- Capability runs: \`bun run eval:capability\` (\`scripts/eval-capability.ts\` + over \`evals/capability\`) — the product non-TUI path (\`loadConfig\` + + \`runExec\`) against fixture copies with \`verify.sh\` graders. +- Latency spans: the PerfTrace harness under \`src/perf\` — \`rollup.ts\` + (TTFT vs stream split), \`assert-spans.ts\` (span assertions), and + \`attribution-report.ts\` (per-turn attribution). +- Read how they invoke before running; extend neither. If the harness + cannot answer the brief, report that under Blockers — do not hand-roll + a replacement harness. + +# Findings route to follow-ups, never silent retunes + +- Report numbers with the exact commands, matrix cells, and harness + outputs behind them so a follow-up can reproduce the probe. +- Policy-looking conclusions (e.g. "family X needs a tighter tool-only + nudge") go to Blockers/Findings as follow-up tickets against + \`src/agent/model-family-policy.ts\` — do not edit the policy here. +- Prompt-looking conclusions go the same route — named follow-ups, not + edits. + +# Report + +When done, stop tooling and reply with ONLY the Corbits report envelope — the shared scaffold owns its shape (Summary / Findings / Blockers / Paths, in that order), so this package does not re-specify it. Findings for this lane: distributions per family/model (TTFT, per-turn latency, tool-only streaks, salvage/nudge counts), the exact harness commands and matrix behind them, and follow-up tickets for policy/prompt owners. + +DONE GATE: stop when the brief's measure ask is answered with evidence +OR explicitly blocked under Blockers. Do not expand into fixes, +retunes, or orchestration. + +OUT OF LANE: shipping product code, tuning prompts or model-family +policy (route to follow-up tickets), building a new harness, fleet +orchestration, architecture essays without measurements.`; + +/** + * 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: "prober", + build: (): string => CARD, +}; diff --git a/agents/prober/src/toolset.ts b/agents/prober/src/toolset.ts new file mode 100644 index 000000000..164abc39d --- /dev/null +++ b/agents/prober/src/toolset.ts @@ -0,0 +1,20 @@ +// Prober worker (CL-7656): measure-only latency/behavior prober per +// family/model. Uses REVIEW_TOOLS. + +const PROBER_TOOLS = [ + "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; + +export const tools: readonly string[] = [...PROBER_TOOLS]; diff --git a/agents/prober/tsconfig.json b/agents/prober/tsconfig.json new file mode 100644 index 000000000..0d7100cbc --- /dev/null +++ b/agents/prober/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 9def48215..84d0c2a99 100644 --- a/bun.lock +++ b/bun.lock @@ -5,7 +5,6 @@ "": { "name": "@corbits/code", "dependencies": { - "@corbits/code-agent-prober": "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 186d93658..c427a0851 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,6 @@ "tar": "^7.5.1" }, "dependencies": { - "@corbits/code-agent-prober": "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/prober/package.test.ts b/src/agent/directors/prober/package.test.ts index 03442ed07..ec1b9f3ac 100644 --- a/src/agent/directors/prober/package.test.ts +++ b/src/agent/directors/prober/package.test.ts @@ -1,25 +1,47 @@ import { describe, expect, test } from "bun:test"; -import { proberPackage } from "@corbits/code-agent-prober"; +import { + director, + tools, + config, + systemPrompt, +} from "@corbits/code-agent-prober"; import { REVIEW_TOOLS } from "../tool-sets.js"; import { DIRECTOR_REGISTRY } from "../registry.js"; import type { DirectorPackage } from "../types.js"; describe("proberPackage", () => { test("workspace package satisfies the director contract and feeds the registry", () => { - const asDirector: DirectorPackage = proberPackage; + const asDirector: DirectorPackage = director; expect(asDirector.id).toBe("prober"); - expect(DIRECTOR_REGISTRY.prober).toBe(proberPackage); - expect([...proberPackage.tools.allow]).toEqual([...REVIEW_TOOLS]); + expect(DIRECTOR_REGISTRY.prober).toBe(director); + expect([...director.tools.allow]).toEqual([...REVIEW_TOOLS]); + expect(new Set(director.tools.allow).size).toBe( + director.tools.allow.length, + ); }); - test("extracted copy stays measure-only and non-spawning", () => { - expect(proberPackage.tools.allow).toContain("read_file"); - expect(proberPackage.tools.allow).toContain("grep"); - expect(proberPackage.tools.allow).not.toContain("spawn_agent"); - expect(proberPackage.tools.allow).not.toContain("ask_operator"); - expect(proberPackage.spawn.maySpawn).toBe(false); - expect(proberPackage.tier).toBe("leaf"); - expect(proberPackage.modelRole).toBe("test"); + 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); }); }); diff --git a/src/agent/directors/registry.ts b/src/agent/directors/registry.ts index 8f2fe33ba..688db63e4 100644 --- a/src/agent/directors/registry.ts +++ b/src/agent/directors/registry.ts @@ -1,5 +1,5 @@ import { director as shakespeareDirector } from "@corbits/code-agent-shakespeare"; -import { proberPackage } from "@corbits/code-agent-prober"; +import { director as proberDirector } from "@corbits/code-agent-prober"; import type { AgentProfile, CapabilityFilter } from "../profile-types.js"; import { director as artistDirector } from "@corbits/code-agent-artist"; import { coderPackage } from "./coder/package.js"; @@ -46,7 +46,7 @@ export const DIRECTOR_REGISTRY: Readonly> = artist: artistDirector, warden: wardenPackage, shakespeare: shakespeareDirector, - prober: proberPackage, + prober: proberDirector, "qa-lead": qaLeadPackage, }; From 6d07880bc02a731f692f3ec3a8dd17a26dba1c54 Mon Sep 17 00:00:00 2001 From: Sawyer Date: Thu, 8 Oct 2026 20:21:07 -0700 Subject: [PATCH 4/9] style(agent-prober): strip redundant commentary from extracted package --- agents/prober/src/agent.ts | 4 ---- agents/prober/src/config.ts | 4 ---- agents/prober/src/director.ts | 4 ---- agents/prober/src/index.ts | 3 --- agents/prober/src/prompt.ts | 5 +---- agents/prober/src/toolset.ts | 3 +-- 6 files changed, 2 insertions(+), 21 deletions(-) diff --git a/agents/prober/src/agent.ts b/agents/prober/src/agent.ts index b9010306c..f1aad00ba 100644 --- a/agents/prober/src/agent.ts +++ b/agents/prober/src/agent.ts @@ -4,10 +4,6 @@ import { } from "@intx/agent"; import { systemPrompt } from "./prompt.js"; -/** - * Prober 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/prober/src/config.ts b/agents/prober/src/config.ts index 4132c6b33..beb453084 100644 --- a/agents/prober/src/config.ts +++ b/agents/prober/src/config.ts @@ -1,10 +1,6 @@ -/** Prober worker — measure-only latency/behavior prober per family/model. */ export const config = { spawn: { maySpawn: false }, tier: "leaf", - // Preserved from the original in-tree card (behavior wins over the contract - // §5 map; test defaults to medium effort in identity.ts, matching the - // measure-only lane). modelRole: "test", } as const satisfies { spawn: { maySpawn: boolean }; diff --git a/agents/prober/src/director.ts b/agents/prober/src/director.ts index cccb26f92..219582290 100644 --- a/agents/prober/src/director.ts +++ b/agents/prober/src/director.ts @@ -2,10 +2,6 @@ import { tools } from "./toolset.js"; import { systemPrompt } from "./prompt.js"; import { config } from "./config.js"; -/** - * Prober worker director card (CL-7656). Structurally satisfies the app's - * `DirectorPackage` (app-side drift-guard asserts assignability). App-independent. - */ export const director = { id: "prober", primaryIntent: diff --git a/agents/prober/src/index.ts b/agents/prober/src/index.ts index 95fc4d646..c2c15f6c6 100644 --- a/agents/prober/src/index.ts +++ b/agents/prober/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. diff --git a/agents/prober/src/prompt.ts b/agents/prober/src/prompt.ts index a676be20e..31db3f6c0 100644 --- a/agents/prober/src/prompt.ts +++ b/agents/prober/src/prompt.ts @@ -52,10 +52,7 @@ OUT OF LANE: shipping product code, tuning prompts or model-family policy (route to follow-up tickets), building a new harness, fleet orchestration, architecture essays without measurements.`; -/** - * Byte-stable system prompt builder. `theme` is the stable voice identifier; - * `build()` returns the identical raw card on every call (no env/interpolation). - */ +// Byte-stable (see prompt authority test). export const systemPrompt = { theme: "prober", build: (): string => CARD, diff --git a/agents/prober/src/toolset.ts b/agents/prober/src/toolset.ts index 164abc39d..b33ba3de9 100644 --- a/agents/prober/src/toolset.ts +++ b/agents/prober/src/toolset.ts @@ -1,5 +1,4 @@ -// Prober worker (CL-7656): measure-only latency/behavior prober per -// family/model. Uses REVIEW_TOOLS. +// PROBER_TOOLS literal; drift-guarded against src/agent/directors/tool-sets.ts. const PROBER_TOOLS = [ "read_file", From 11273199683af96baf68884f7b06ddb1c357281e Mon Sep 17 00:00:00 2001 From: Sawyer Date: Thu, 8 Oct 2026 20:22:19 -0700 Subject: [PATCH 5/9] style(agent-prober): strip redundant commentary from extracted package --- agents/prober/src/agent.ts | 4 ++-- agents/prober/src/config.ts | 2 +- agents/prober/src/director.ts | 2 +- agents/prober/src/index.ts | 2 +- agents/prober/src/prompt.ts | 4 +--- agents/prober/src/toolset.ts | 4 +--- 6 files changed, 7 insertions(+), 11 deletions(-) diff --git a/agents/prober/src/agent.ts b/agents/prober/src/agent.ts index f1aad00ba..c7a9057e7 100644 --- a/agents/prober/src/agent.ts +++ b/agents/prober/src/agent.ts @@ -10,11 +10,11 @@ export function defineAgent(): AgentDefinition { return coreDefineAgent({ id: "prober", 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: "prober" }, }); -} +} \ No newline at end of file diff --git a/agents/prober/src/config.ts b/agents/prober/src/config.ts index beb453084..2f9c4b761 100644 --- a/agents/prober/src/config.ts +++ b/agents/prober/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/prober/src/director.ts b/agents/prober/src/director.ts index 219582290..fa4fe2ee7 100644 --- a/agents/prober/src/director.ts +++ b/agents/prober/src/director.ts @@ -19,4 +19,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/prober/src/index.ts b/agents/prober/src/index.ts index c2c15f6c6..e87040867 100644 --- a/agents/prober/src/index.ts +++ b/agents/prober/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/prober/src/prompt.ts b/agents/prober/src/prompt.ts index 31db3f6c0..917d4c52b 100644 --- a/agents/prober/src/prompt.ts +++ b/agents/prober/src/prompt.ts @@ -1,5 +1,4 @@ -// Prober raw director card (CL-7656). Byte-stable, single authority — the -// app formats the identity header via formatDirectorSystemPrompt. +// The app formats the identity header via formatDirectorSystemPrompt. const CARD = `You are ProberDirector (Prober), a specialist in Corbits Code. @@ -52,7 +51,6 @@ OUT OF LANE: shipping product code, tuning prompts or model-family policy (route to follow-up tickets), building a new harness, fleet orchestration, architecture essays without measurements.`; -// Byte-stable (see prompt authority test). export const systemPrompt = { theme: "prober", build: (): string => CARD, diff --git a/agents/prober/src/toolset.ts b/agents/prober/src/toolset.ts index b33ba3de9..9bda52acf 100644 --- a/agents/prober/src/toolset.ts +++ b/agents/prober/src/toolset.ts @@ -1,5 +1,3 @@ -// PROBER_TOOLS literal; drift-guarded against src/agent/directors/tool-sets.ts. - const PROBER_TOOLS = [ "read_file", "grep", @@ -16,4 +14,4 @@ const PROBER_TOOLS = [ "delete_file", ] as const; -export const tools: readonly string[] = [...PROBER_TOOLS]; +export const tools: readonly string[] = [...PROBER_TOOLS]; \ No newline at end of file From 8bd28a9b449f638b917b586b8989bf973763a3c6 Mon Sep 17 00:00:00 2001 From: "user.email" Date: Thu, 8 Oct 2026 22:22:29 -0700 Subject: [PATCH 6/9] chore(dead-exports): allowlist cl-9806-extract-corbits-agent-prober 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 bf9856198..0003b259a 100644 --- a/scripts/dead-export-allowlist.txt +++ b/scripts/dead-export-allowlist.txt @@ -65,3 +65,7 @@ agents/shakespeare/src/index.ts: agent agents/shakespeare/src/index.ts: defineAgent agents/shakespeare/src/config.ts: satisfies agents/shakespeare/src/config.ts: boolean +agents/prober/src/index.ts: agent +agents/prober/src/index.ts: defineAgent +agents/prober/src/config.ts: satisfies +agents/prober/src/config.ts: boolean From 077dc59bbf118a04c0f60a98f99564939ce908e2 Mon Sep 17 00:00:00 2001 From: "user.email" Date: Thu, 8 Oct 2026 22:31:13 -0700 Subject: [PATCH 7/9] style(agent-prober): restore formatting in package sources --- agents/prober/src/agent.ts | 2 +- agents/prober/src/config.ts | 2 +- agents/prober/src/director.ts | 2 +- agents/prober/src/index.ts | 2 +- agents/prober/src/toolset.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/agents/prober/src/agent.ts b/agents/prober/src/agent.ts index c7a9057e7..b9b00e20d 100644 --- a/agents/prober/src/agent.ts +++ b/agents/prober/src/agent.ts @@ -17,4 +17,4 @@ export function defineAgent(): AgentDefinition { }, tags: { fleet: "0.3.36", lane: "prober" }, }); -} \ No newline at end of file +} diff --git a/agents/prober/src/config.ts b/agents/prober/src/config.ts index 2f9c4b761..beb453084 100644 --- a/agents/prober/src/config.ts +++ b/agents/prober/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/prober/src/director.ts b/agents/prober/src/director.ts index fa4fe2ee7..219582290 100644 --- a/agents/prober/src/director.ts +++ b/agents/prober/src/director.ts @@ -19,4 +19,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/prober/src/index.ts b/agents/prober/src/index.ts index e87040867..c2c15f6c6 100644 --- a/agents/prober/src/index.ts +++ b/agents/prober/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/prober/src/toolset.ts b/agents/prober/src/toolset.ts index 9bda52acf..9ed7b99ae 100644 --- a/agents/prober/src/toolset.ts +++ b/agents/prober/src/toolset.ts @@ -14,4 +14,4 @@ const PROBER_TOOLS = [ "delete_file", ] as const; -export const tools: readonly string[] = [...PROBER_TOOLS]; \ No newline at end of file +export const tools: readonly string[] = [...PROBER_TOOLS]; From b7f1e822bbb4a6addd6a7aef63b53a693a8d03a6 Mon Sep 17 00:00:00 2001 From: "user.email" Date: Thu, 8 Oct 2026 23:53:01 -0700 Subject: [PATCH 8/9] fix(agent-prober): drop hardcoded inference source and release tag --- agents/prober/src/agent.ts | 5 +---- agents/prober/src/toolset.ts | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/agents/prober/src/agent.ts b/agents/prober/src/agent.ts index b9b00e20d..b9e59f6e4 100644 --- a/agents/prober/src/agent.ts +++ b/agents/prober/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: "prober" }, + inference: { sources: [] }, }); } diff --git a/agents/prober/src/toolset.ts b/agents/prober/src/toolset.ts index 9ed7b99ae..d8041a3ef 100644 --- a/agents/prober/src/toolset.ts +++ b/agents/prober/src/toolset.ts @@ -1,4 +1,4 @@ -const PROBER_TOOLS = [ +export const tools: readonly string[] = [ "read_file", "grep", "search_files", @@ -13,5 +13,3 @@ const PROBER_TOOLS = [ "edit_file", "delete_file", ] as const; - -export const tools: readonly string[] = [...PROBER_TOOLS]; From 47c1b4d7e16c2c0fa60b2520a6e3eb987d27c9b2 Mon Sep 17 00:00:00 2001 From: "user.email" Date: Fri, 9 Oct 2026 00:03:42 -0700 Subject: [PATCH 9/9] chore(dead-exports): bump scanned-file floor for extracted agent packages --- scripts/dead-export-guard.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/dead-export-guard.json b/scripts/dead-export-guard.json index 9b2bf9e8f..e29ca9e6c 100644 --- a/scripts/dead-export-guard.json +++ b/scripts/dead-export-guard.json @@ -1,5 +1,5 @@ { "tsconfig": "tsconfig.json", "tsPruneArgs": ["-p", "tsconfig.json"], - "minScannedFiles": 1130 + "minScannedFiles": 1240 }