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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions agents/explorer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# @corbits/code-agent-explorer

## What this is

Ready `@corbits/code-agent-explorer` agent + independently importable components:
`agent`, `defineAgent`, `director`, `tools`, `systemPrompt`, `config`. Explorer is
the read-only mapping & search worker: it maps the codebase against the brief and
reports scannable findings — it never implements, reviews, or discovers the fleet.

## Consume (runLocal)

```ts
import { agent } from "@corbits/code-agent-explorer";
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-explorer";
defineAgent({ director, ... }); // or swap tools / systemPrompt / config
```

Each of `agent`, `defineAgent`, `director`, `tools`, `systemPrompt`, `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 `READ_TOOLS` surface constant in
`src/agent/directors/tool-sets.ts` (explorer is deliberately read-only — no
`write_file`/`edit_file`/`delete_file`); drift is enforced by the in-tree
drift-guard `src/agent/directors/explorer/package.test.ts`.
13 changes: 13 additions & 0 deletions agents/explorer/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "@corbits/code-agent-explorer",
"version": "0.1.0",
"private": true,
"type": "module",
"license": "SEE LICENSE IN LICENSE.md",
"exports": {
".": {
"types": "./src/index.ts",
"default": "./src/index.ts"
}
}
}
23 changes: 23 additions & 0 deletions agents/explorer/src/agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Explorer assembled agent — ready unit + package defineAgent wrapper. Calls
// `@intx/agent`'s `defineAgent` directly (no Corbits bridge). Tool mounting is
// consumer/app-side: `tools` here is [] (the allowlist surface is exported from
// `./toolset.js` and wired by the app harness).

import {
defineAgent as coreDefineAgent,
type AgentDefinition,
} from "@intx/agent";

import { systemPrompt } from "./prompt.js";

export const agent: AgentDefinition = defineAgent();

export function defineAgent(): AgentDefinition {
return coreDefineAgent({
id: "explorer",
systemPrompt: systemPrompt.build(),
tools: [],
capabilities: [],
inference: { sources: [] },
});
}
9 changes: 9 additions & 0 deletions agents/explorer/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const config = {
spawn: { maySpawn: false },
tier: "leaf",
modelRole: "explore",
} as const satisfies {
spawn: { maySpawn: boolean; allowlist?: readonly string[] };
tier: string;
modelRole: string;
};
22 changes: 22 additions & 0 deletions agents/explorer/src/director.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Explorer director card; imports @intx/* only. The app asserts this satisfies
// `DirectorPackage` in-tree (src/agent/directors/explorer/package.test.ts).
import { tools } from "./toolset.js";
import { systemPrompt } from "./prompt.js";
import { config } from "./config.js";

export const director = {
id: "explorer",
primaryIntent: "Map and read the codebase; no product edits",
outOfLane: [
"product write paths",
"drive-by fixes",
"shipping features",
"review severity theater",
],
description: "Read-only exploration",
systemPrompt: systemPrompt.build(),
tools: { allow: tools },
spawn: config.spawn,
modelRole: config.modelRole,
tier: config.tier,
} as const;
8 changes: 8 additions & 0 deletions agents/explorer/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Public surface — re-exports only, so the package imports no Corbits code
// (the app asserts the director contract in-tree via drift-guard). No `workflow`
// export: workflows consume `agent`.
export { agent, defineAgent } from "./agent.js";
export { director } from "./director.js";
export { tools } from "./toolset.js";
export { systemPrompt } from "./prompt.js";
export { config } from "./config.js";
Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
import type { DirectorPackage } from "../types.js";
import { READ_TOOLS } from "../tool-sets.js";

/**
* Explorer worker (CL-7020 / CL-7015 rename from explore).
* Map/read against the brief — scannable findings only; never implement, review, or discover the fleet.
*/
export const explorerPackage: DirectorPackage = {
id: "explorer",
primaryIntent: "Map and read the codebase; no product edits",
outOfLane: [
"product write paths",
"drive-by fixes",
"shipping features",
"review severity theater",
],
description: "Read-only exploration",
systemPrompt: `You are ExplorerDirector (Explorer), a specialist in Corbits Code.
// Single prompt authority: `build()` is pure and byte-stable — it returns an
// identical string on every call.
const CARD = `You are ExplorerDirector (Explorer), a specialist in Corbits Code.

PRIMARY INTENT: map and read the codebase to answer the brief. Read, search, report. Do not implement product changes.
You are the explore lane only — not Coder, not Reviewer, not an orchestrator. Do not spawn specialists. Blinders on: do not discover or enumerate the fleet; stay inside the brief's question.
Expand All @@ -30,9 +15,13 @@ DONE GATE: Stop when every success_criteria item from the brief is answered OR e

FINDINGS SHAPE: Findings must be a scannable map — key paths, symbols, call flow / ownership — not optional prose dump. Cite paths. No drive-by refactors, no feature work, no review severity theater.

OUT OF LANE: product writes, drive-by fixes, shipping features, review severity theater, orchestration, spawning specialists, fleet discovery, becoming Coder/Reviewer/orchestrator as primary.`,
tools: { allow: READ_TOOLS },
spawn: { maySpawn: false },
tier: "leaf",
modelRole: "explore",
FINISH BIAS: Prefer one thorough pass then report. Expand Findings, change approach, or write the final report — do not keep re-reading the same paths.

OUT OF LANE: product writes, drive-by fixes, shipping features, review severity theater, orchestration, spawning specialists, fleet discovery, becoming Coder/Reviewer/orchestrator as primary.`;

export const theme = "explorer";

export const systemPrompt = {
theme,
build: (): string => CARD,
};
15 changes: 15 additions & 0 deletions agents/explorer/src/toolset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Explorer read surface only: literal expansion of the `READ_TOOLS` constant in
// src/agent/directors/tool-sets.ts (the single tool authority). Drift is enforced
// in-tree by src/agent/directors/explorer/package.test.ts.
export const tools = [
"read_file",
"grep",
"search_files",
"list_dir",
"lsp",
"run_shell",
"web_fetch",
"web_search",
"skill_search",
"use_skill",
] as const;
7 changes: 7 additions & 0 deletions agents/explorer/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"noEmit": true
},
"include": ["src/**/*.ts"]
}
5 changes: 5 additions & 0 deletions bun.lock

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

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

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

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

describe("explorerPackage", () => {
test("workspace package satisfies the director contract and feeds the registry", () => {
const asDirector: DirectorPackage = director;
expect(asDirector.id).toBe("explorer");
expect(DIRECTOR_REGISTRY.explorer).toBe(director);
// Explorer is deliberately read-only: READ_TOOLS, not REVIEW_TOOLS.
expect([...director.tools.allow]).toEqual([...READ_TOOLS]);
expect(new Set(director.tools.allow).size).toBe(
director.tools.allow.length,
);
});

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

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

test("tools surface matches READ_TOOLS and is leaf/scoped, read-only", () => {
expect([...tools]).toEqual([...READ_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");
// Read-only: no product write tools.
expect(tools).not.toContain("write_file");
expect(tools).not.toContain("edit_file");
expect(tools).not.toContain("delete_file");
});

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