refactor(self-mod): drop request_rebuild — approvals now bundle rebuild+restart

install_packages and add_mcp_server already did the right thing on approve
(install auto-rebuilt+killed, add_mcp_server just killed), so request_rebuild
was redundant plumbing agents sometimes called after an install — wasting an
admin approval round-trip. Delete it end-to-end:

- container/agent-runner/src/mcp-tools/self-mod.ts: remove requestRebuild
  tool + registration; update install_packages description.
- src/modules/self-mod/{request,apply,index}.ts: drop handleRequestRebuild
  + applyRequestRebuild + registrations; rewrite the rebuild-failed notify
  to point admins at retrying install_packages instead.
- src/modules/{approvals,self-mod}/{agent,project}.md and skill/self-
  customize/SKILL.md: scrub agent-facing references; clarify that
  add_mcp_server needs no rebuild (bun runs TS directly).
- docs/{module-contract,architecture-diagram,checklist,db-central,shared-
  source,v1-vs-v2/*}.md, CLAUDE.md, pending-approvals migration comment,
  approvals/index.ts docstring, REFACTOR.md: trailing references.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-04-22 17:28:36 +03:00
parent e64bdb3016
commit 3b8240a91b
20 changed files with 97 additions and 151 deletions

View File

@@ -1,9 +1,13 @@
/**
* Self-modification MCP tools: install_packages, add_mcp_server, request_rebuild.
* Self-modification MCP tools: install_packages, add_mcp_server.
*
* All three are fire-and-forget — the tool writes a system action row and
* returns immediately. The host processes the request (including admin
* approval) and notifies the agent via a chat message when complete.
* Both are fire-and-forget — the tool writes a system action row and returns
* immediately. The host processes the request (including admin approval)
* and notifies the agent via a chat message when complete. Admin approval
* is approval to apply the change: `install_packages` auto-rebuilds the
* per-agent image and restarts the container; `add_mcp_server` just
* updates `container.json` and restarts (bun runs TS directly — no build
* step needed for a pure MCP wiring change).
*
* Package names are sanitized here at the tool boundary AND re-validated on
* the host side (defense in depth).
@@ -36,7 +40,7 @@ export const installPackages: McpToolDefinition = {
tool: {
name: 'install_packages',
description:
'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.',
'Install apt and/or npm packages into YOUR per-agent container image. Requires admin approval; fire-and-forget. On approval, the image is rebuilt and the container is restarted automatically.',
inputSchema: {
type: 'object' as const,
properties: {
@@ -113,32 +117,4 @@ export const addMcpServer: McpToolDefinition = {
},
};
export const requestRebuild: McpToolDefinition = {
tool: {
name: 'request_rebuild',
description:
'Rebuild YOUR container image to pick up approved `install_packages` / `add_mcp_server` changes. Requires admin approval; fire-and-forget.',
inputSchema: {
type: 'object' as const,
properties: {
reason: { type: 'string', description: 'Why the rebuild is needed' },
},
},
},
async handler(args) {
const requestId = generateId();
writeMessageOut({
id: requestId,
kind: 'system',
content: JSON.stringify({
action: 'request_rebuild',
reason: (args.reason as string) || '',
}),
});
log(`request_rebuild: ${requestId}`);
return ok(`Rebuild request submitted. You will be notified when admin approves or rejects.`);
},
};
registerTools([installPackages, addMcpServer, requestRebuild]);
registerTools([installPackages, addMcpServer]);

View File

@@ -11,9 +11,9 @@ You can modify your own environment. Different kinds of changes have different w
**What needs to change?**
- **Your CLAUDE.md or files in your workspace** → Edit directly, no approval needed. Your workspace (`/workspace/agent/`) is persisted on the host.
- **System package (apt) or global npm package** → `install_packages``request_rebuild`. Requires admin approval.
- **MCP server** → `add_mcp_server``request_rebuild`. No approval needed, but rebuild required to apply.
- **`CLAUDE.local.md` or files in your workspace** → Edit directly, no approval needed. Your workspace (`/workspace/agent/`) is persisted on the host. (Note: the composed `CLAUDE.md` itself is read-only and regenerated every spawn — write to `CLAUDE.local.md` instead.)
- **System package (apt) or global npm package** → `install_packages`. Requires admin approval. On approval, image rebuild + container restart happen automatically.
- **MCP server** → `add_mcp_server`. Requires admin approval. On approval, container restarts with the new server wired up (no rebuild — bun runs TS directly).
- **Your source code or Dockerfile** → Delegate to a builder agent via `create_agent` (see below).
- **A new specialist capability** → `create_agent` to spin up a dedicated agent for it.
@@ -25,7 +25,7 @@ For anything that requires editing source files (your own code, Dockerfile, etc.
2. Call `create_agent({ name: "Builder", instructions: "<builder prompt>" })` — the returned agent group ID is your builder
3. Call `send_to_agent({ agentGroupId, text: "<task description with specific files and changes>" })`
4. The builder works in its own container, makes the changes, and reports back
5. You review the builder's summary, confirm with the user, then call `request_rebuild` if the changes require it
5. You review the builder's summary and confirm with the user. Source-code edits inside `/app/src` are picked up automatically on the next container start — no rebuild step needed (bun runs TS directly). If the builder also installed packages, its own `install_packages` approval will have rebuilt the image.
### Builder Agent Instructions (use as CLAUDE.md when creating)
@@ -64,12 +64,11 @@ The limits are **per builder task**, not per session. A 500-line feature is fine
User: "Can you add a tool for reading RSS feeds?"
1. Check [mcp.so](https://mcp.so) for an existing RSS MCP server
2. If one exists → `add_mcp_server({ name: "rss", command: "npx", args: ["some-rss-mcp"] })``request_rebuild` → done
2. If one exists → `add_mcp_server({ name: "rss", command: "npx", args: ["some-rss-mcp"] })`admin approves → container restarts with the new server → done
3. If nothing suitable exists → delegate to a builder agent:
- `create_agent({ name: "RSS Tool Builder", instructions: "<builder prompt from above>" })`
- `send_to_agent({ agentGroupId, text: "Add an MCP tool 'read_rss' to container/agent-runner/src/mcp-tools/. It should fetch an RSS URL and return the latest N items. Register it in mcp-tools/index.ts. Target: <200 new lines." })`
- Wait for builder's report
- `request_rebuild` if needed
- Wait for builder's report — new tool code is picked up on the next container start (bun runs TS directly)
## Example: Installing a System Tool
@@ -78,10 +77,8 @@ User: "Can you transcribe audio?"
1. Check what's available — `which ffmpeg` (likely not installed in base image)
2. Decide approach: `@xenova/transformers` (npm, workspace-local) or `whisper.cpp` (apt + compile)
3. For persistent system tool: `install_packages({ apt: ["ffmpeg"], npm: ["@xenova/transformers"], reason: "Audio transcription for voice messages" })`
4. Wait for admin approval
5. `request_rebuild({ reason: "Apply audio transcription packages" })`
6. Wait for admin approval
7. Test the new capability once the container restarts
4. Wait for admin approval — on approve, the image is rebuilt and your container is restarted automatically
5. Test the new capability once the container restarts
## When NOT to Self-Customize