refactor(v2): remove builder-agent dev-agent/worktree/swap flow

The dev-agent-in-worktree approach for source self-modification is abandoned
in favor of a direct draft/activate flow with OS-level RO enforcement
(planned, not yet implemented). Strip the whole subgraph:
src/builder-agent/, pending-swaps DB module + migration 006, builder-agent
MCP tools, and all host wiring (startup sweep, approval routing, deadman,
worktree mount, freeze gate). Tool descriptions in self-mod.ts / agents.ts
no longer cross-reference create_dev_agent. CLAUDE.md + v2-checklist updated
to describe the new direction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-04-15 21:14:39 +03:00
parent 20a24dfd13
commit 81d45b5be9
29 changed files with 9 additions and 3644 deletions

View File

@@ -31,7 +31,7 @@ export const createAgent: McpToolDefinition = {
tool: {
name: 'create_agent',
description:
"Create a long-lived companion sub-agent (research assistant, task manager, specialist) — the name becomes your destination for it. NOT for source-code changes — use `create_dev_agent` for those. Admin-only. Fire-and-forget.",
'Create a long-lived companion sub-agent (research assistant, task manager, specialist) — the name becomes your destination for it. Admin-only. Fire-and-forget.',
inputSchema: {
type: 'object' as const,
properties: {

View File

@@ -1,116 +0,0 @@
/**
* Builder-agent MCP tools: request_dev_changes (for originating agents) and
* request_swap (for dev agents).
*
* Both are fire-and-forget: the tool writes a system action row to
* messages_out and returns immediately. The host processes the request and
* notifies the agent via a chat message when complete.
*
* See `src/builder-agent/handlers.ts` on the host for the receive side.
*/
import { writeMessageOut } from '../db/messages-out.js';
import type { McpToolDefinition } from './types.js';
function log(msg: string): void {
console.error(`[mcp-tools] ${msg}`);
}
function generateId(): string {
return `msg-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
}
function ok(text: string) {
return { content: [{ type: 'text' as const, text }] };
}
function err(text: string) {
return { content: [{ type: 'text' as const, text: `Error: ${text}` }], isError: true };
}
export const createDevAgent: McpToolDefinition = {
tool: {
name: 'create_dev_agent',
description:
"Spawn a dev agent to edit NanoClaw's own source code — new built-in MCP tools, runner/host bug fixes, new skill files, Dockerfile/package.json/migration changes, writing a new MCP server from scratch. Heaviest self-mod path: new container, git worktree, admin approval, swap-and-restart.\n\nPrefer lighter tools when they fit: `install_packages` (new apt/npm dep in your container), `add_mcp_server` (wire an EXISTING third-party server you can invoke by command+args), `trigger_credential_collection` (API key/token), `create_agent` (long-lived companion sub-agent), `request_rebuild` (rebuild after approved config change).\n\nTwo-step flow: (1) call with just a name — does NOT start work, (2) after the 'ready' notification, send task details via `<message to=\"<name>\">`. Do not include task details in this call.",
inputSchema: {
type: 'object' as const,
properties: {
name: {
type: 'string',
description:
'Short descriptive destination name for the dev agent (e.g. "dev-welcome-message", "dev-fix-typo"). Becomes the local destination you address it by. Tearing down a previous dev agent for this group is automatic on create.',
},
},
required: ['name'],
},
},
async handler(args) {
const name = (args.name as string)?.trim();
if (!name) return err('name is required');
const requestId = generateId();
writeMessageOut({
id: requestId,
kind: 'system',
content: JSON.stringify({
action: 'create_dev_agent',
requestId,
name,
}),
});
log(`create_dev_agent: ${requestId} → "${name}"`);
return ok(
`Dev agent creation submitted. You will be notified when it is ready. When you see that notification, send it a message with <message to="${name}">...task details here...</message> to kick off the work. The dev agent does NOT start working until you message it.`,
);
},
};
export const requestSwap: McpToolDefinition = {
tool: {
name: 'request_swap',
description:
'From a dev agent: submit your committed worktree changes for admin approval. The summaries become the human-readable portion of the approval card. Fire-and-forget.',
inputSchema: {
type: 'object' as const,
properties: {
overall_summary: {
type: 'string',
description:
'Overall summary of the code change: what it does, why, and any risk. This is what the admin/owner reads first, so be concrete.',
},
per_file_summaries: {
type: 'object',
description:
'Map of relative worktree path → one-sentence explanation of what changed in that file. Every changed file should have an entry.',
additionalProperties: { type: 'string' },
},
},
required: ['overall_summary', 'per_file_summaries'],
},
},
async handler(args) {
const overall = (args.overall_summary as string)?.trim();
const perFile = args.per_file_summaries as Record<string, string> | undefined;
if (!overall) return err('overall_summary is required');
if (!perFile || Object.keys(perFile).length === 0) return err('per_file_summaries is required and must be non-empty');
const requestId = generateId();
writeMessageOut({
id: requestId,
kind: 'system',
content: JSON.stringify({
action: 'request_swap',
overallSummary: overall,
perFileSummaries: perFile,
}),
});
log(`request_swap: ${requestId}${Object.keys(perFile).length} file(s)`);
return ok(
`Code change submitted. The host will classify the diff and route it for admin/owner approval. You will be notified once classification completes.`,
);
},
};
export const builderAgentTools: McpToolDefinition[] = [createDevAgent, requestSwap];

View File

@@ -16,7 +16,6 @@ import { interactiveTools } from './interactive.js';
import { agentTools } from './agents.js';
import { selfModTools } from './self-mod.js';
import { credentialTools } from './credentials.js';
import { builderAgentTools } from './builder-agent.js';
function log(msg: string): void {
console.error(`[mcp-tools] ${msg}`);
@@ -29,7 +28,6 @@ const allTools: McpToolDefinition[] = [
...agentTools,
...selfModTools,
...credentialTools,
...builderAgentTools,
];
const toolMap = new Map<string, McpToolDefinition>();

View File

@@ -35,7 +35,7 @@ export const installPackages: McpToolDefinition = {
tool: {
name: 'install_packages',
description:
'Install apt and/or npm packages into YOUR per-agent container image. Prefer this over `create_dev_agent` when the request is just to make a package available. Requires admin approval; fire-and-forget. After approval, call `request_rebuild` to apply.',
'Install apt and/or npm packages into YOUR per-agent container image. Requires admin approval; fire-and-forget. After approval, call `request_rebuild` to apply.',
inputSchema: {
type: 'object' as const,
properties: {
@@ -77,7 +77,7 @@ export const addMcpServer: McpToolDefinition = {
tool: {
name: 'add_mcp_server',
description:
"Wire an EXISTING third-party MCP server into YOUR per-agent runtime config — you must already know the exact `command` + `args` to invoke it (e.g. `npx @modelcontextprotocol/server-github`). NOT for writing a new tool or server from scratch — use `create_dev_agent` for that. Requires admin approval; fire-and-forget.",
'Wire an EXISTING third-party MCP server into YOUR per-agent runtime config — you must already know the exact `command` + `args` to invoke it (e.g. `npx @modelcontextprotocol/server-github`). Requires admin approval; fire-and-forget.',
inputSchema: {
type: 'object' as const,
properties: {