Files
nanoclaw/src/modules/approvals/agent.md
gavrielc a4573395d9 refactor(modules): extract approvals + interactive as registry-based modules
Phase 2 / PR #3 of the module refactor. Moves the approval and interactive-
question flows out of core and into src/modules/, wired through the response
dispatcher and delivery action registries.

New modules:
- src/modules/interactive/ — registers a response handler that claims
  pending_questions rows, writes question_response to the session DB, wakes
  the container. createPendingQuestion call stays inline in delivery.ts
  (guarded by hasTable) per plan.
- src/modules/approvals/ — registers 3 delivery actions (install_packages,
  request_rebuild, add_mcp_server), a response handler for pending_approvals
  (including OneCLI action fall-through), an adapter-ready hook that boots
  the OneCLI manual-approval handler, and a shutdown hook that stops it.
  OneCLI implementation (src/onecli-approvals.ts) moves into the module.

Core lifecycle hooks added (narrow, not registries):
- onDeliveryAdapterReady(cb) in delivery.ts — fires when setDeliveryAdapter
  runs (or immediately if already set). Used by approvals for OneCLI boot.
- onShutdown(cb) in index.ts — fires on SIGTERM/SIGINT. Used by approvals
  for OneCLI teardown.
- getDeliveryAdapter() getter in delivery.ts — for live-flow adapter access
  in registered delivery actions.

Core shrinks: delivery.ts 911 → 665 lines, index.ts 405 → 224 lines.
dispatchResponse now logs "Unclaimed response" instead of falling through
to an inline handler — the inline fallback moved into the two modules.

Migration files renamed to the module-<name>-<short>.ts convention:
- 003-pending-approvals.ts → module-approvals-pending-approvals.ts
- 007-pending-approvals-title-options.ts → module-approvals-title-options.ts
Migration.name fields unchanged so existing DBs treat them as already-applied.

Degradation verified: emptying the modules barrel builds clean and 137/137
tests pass. Actions would log "Unknown system action"; button clicks would
log "Unclaimed response".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 15:16:53 +03:00

2.4 KiB

Self-modification tools (require admin approval)

Three fire-and-forget tools change your container image or config. Each sends an approval card to an admin's DM; you get notified via system chat on approve/reject.

install_packages

Add apt and/or npm packages to your container image. On approval, the config is updated AND the image is rebuilt in the same step — you'll get a follow-up prompt ~5s after rebuild telling you to verify the packages are available.

install_packages({
  apt: ["ripgrep", "jq"],              // names only, no version specs or flags
  npm: ["@anthropic-ai/sdk"],          // global install
  reason: "need rg for fast code search"
})
  • Max 20 packages per request.
  • Names must match strict regex (blocks shell injection via vim; curl evil.com).
  • After approval: rebuild runs automatically. You do NOT need to call request_rebuild separately.

add_mcp_server

Wire an EXISTING third-party MCP server into your runtime config. You must already know the exact command and args.

add_mcp_server({
  name: "github",
  command: "npx",
  args: ["@modelcontextprotocol/server-github"],
  env: { GITHUB_TOKEN: "..." }
})
  • Does NOT install packages. Use install_packages first if the command isn't already available.
  • On approval, container is killed so the next message wakes it with the new server wired up.

request_rebuild

Rebuild your container image. Only useful if you've already landed install_packages approvals whose rebuild step failed, or if you're recovering from a bad config edit.

request_rebuild({ reason: "previous install_packages rebuild failed" })

How approval works

You won't see the admin's response in your current turn. After approval, the container is killed and next time a message arrives your container starts fresh on the new image. If a follow-up system prompt fires (as with install_packages), you'll see it and should act on it — verify the change, report to the user.

If denied, you'll get a chat message telling you the request was rejected. Do not retry automatically; explain to the user what was denied.

Credential approvals (OneCLI)

When you call an external API that requires credentials, OneCLI may prompt an admin for approval before releasing the token. This happens transparently: the HTTP call blocks until admin approves or denies. No action needed from you — just make the call. If it errors out with a credential failure, tell the user and stop.