feat!: remove the ACP adapter, bump the toolchain, add the cloudflare-docs MCP server - #20
Merged
Conversation
BREAKING CHANGE: the project is now mounted at /workspace/project, not /workspace. Remove ACP - Delete run_acp.sh, the baked start-acp.sh entrypoint, the build-gate presence check, and ENV CLAUDE_CODE_EXECUTABLE (its only consumer was the ACP adapter). - Drop @agentclientprotocol/claude-agent-acp from the locked toolchain. That also removes @agentclientprotocol/sdk and @anthropic-ai/claude-agent-sdk with its 8 per-platform Claude Code binaries, so the image no longer ships a second, separately-sourced Claude binary — the supply-chain residual documented in SECURITY.md is closed, and the CLAUDE_CODE_EXECUTABLE pin that mitigated it is no longer needed. The npm ci layer drops from ~1.47 GB to 1030.7 MB and the image from 2.52 GB to 2.01 GB. - Dev Container is kept; it never depended on ACP. Mount the project one level down (breaking) - codebase-memory-mcp refuses to index any first-level path as a root since v0.10.0: index_repository on /workspace answers "path is too broad to index as one root". The rule comes from upstream PR #1464 (src/foundation/workspace.c), motivated by issue #1241 (OOM from indexing ~), and cannot be lifted — `allow-root /workspace` answers "refused" and --approve-sensitive does not apply. Verified: /workspace and /proj are refused; /workspace/repo, /srv/x and /w/x index fine. - All four entrypoints (run_claude.sh, debug-shell.sh, the claude-box launcher from install.sh, the Dev Container) now mount at /workspace/project, and the project key in claude-config.json / install-mcp-servers.sh / diagnose-mcp.sh moves with them. Dependencies - claude-code 2.1.221 -> 2.1.238, openspec 1.7.0 -> 1.10.0, pnpm 11.18.0 -> 11.22.0, eslint 10.8.0 -> 10.8.1; lockfile regenerated inside node:22 (lockfileVersion 3). typescript stays at 6.0.3 — 7.x still breaks ts-node. - RTK v0.44.2 -> v0.45.0, codebase-memory-mcp v0.9.0 -> v0.10.8, both sha256 refreshed per arch. - caveman stays at v1.9.1. v2.2.0 adds a floating dependency @caveman-ai/cli (^1.1.0) whose own `caveman` bin shadows the installer's under npx, so the documented invocation no longer reaches bin/install.js; that dependency is also an account/cloud CLI that fetches companion Go binaries at runtime, which this image forbids. - npm audit re-derived: 2 high, both rows of the single advisory GHSA-w48q-cv73-mx4w (<1.24.0) via perplexity-mcp; no fix available, still an accepted residual. The previously patched form-data/hono/ip-address survived the regeneration. codebase-memory-mcp hardening - Bake CBM_ALLOWED_ROOT=/workspace, now possible because /workspace is the single entrypoint path. Verified as a live control: indexing /home/agent is refused. - Turn the graph UI off at build time (config set ui_enabled false). Upstream defaults it to true, so the daemon otherwise binds 127.0.0.1:9749 — contrary to the upstream README, which documents the UI as opt-in. Verified: no listening socket in the built image. Add cloudflare-docs MCP (type: http, no API key, no package to install). claude mcp list shows all six servers connected in ~5.7s. Docs: README/CLAUDE.md/SECURITY.md updated throughout, including re-measured numbers (15 MCP tools vs 8, 231 nodes / 279 edges, 280 MB binary, layer sizes) and two pre-existing drifts fixed — OpenSpec is initialized into /home/claude (not the project mount), and caveman's hooks come from the plugin manifest rather than settings.json. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AXpQVijvq37fmKbLVWhgZC
The array granted access to /workspace/{input,output,data,temp}, which have not
existed since the container moved to single read-write mode — nothing creates
them and the README says as much. Carrying them forward to /workspace/project
would have preserved a knob that grants nothing. The project mount itself needs
no entry here.
Verified in the rebuilt image: the project key is /workspace/project, permissions
carry only the allow list, and all six MCP servers still connect.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AXpQVijvq37fmKbLVWhgZC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Removes the ACP (Agent Client Protocol) adapter and every constraint it imposed, bumps the pinned toolchain, and adds the
cloudflare-docsMCP server. Docs are brought back in line with what the image actually does, including re-measured numbers.Warning
Breaking: the project is now mounted at
/workspace/project, not/workspace. Anything scripted against the old in-container path needs updating.Remove the ACP adapter
run_acp.sh, the bakedstart-acp.shentrypoint, the build-gate presence check, andENV CLAUDE_CODE_EXECUTABLE(whose only consumer was the adapter) are gone, along with the@agentclientprotocol/claude-agent-acpdependency.That also drops
@agentclientprotocol/sdkand@anthropic-ai/claude-agent-sdkwith its 8 per-platform Claude Code binaries, so the image no longer ships a second, separately-sourced Claude binary. The supply-chain residual documented inSECURITY.mdis therefore closed, and theCLAUDE_CODE_EXECUTABLEpin that mitigated it is no longer needed.Measured effect: the
npm cilayer drops from ~1.47 GB to 1030.7 MB, and the image from 2.52 GB to 2.01 GB.The Dev Container is kept — it never depended on ACP (its
node-user removal and raised pids cap have their own reasons).Mount the project one level down (breaking)
codebase-memory-mcprefuses to index any first-level path as a root since v0.10.0:The rule comes from upstream PR #1464 (
src/foundation/workspace.{c,h}, first shipped in v0.10.0), motivated by issue #1241 — an OOM from indexing~. It cannot be lifted:allow-root /workspaceanswersrefused, and--approve-sensitivedoes not apply to it (PR #1472 says so explicitly, and it was verified here).Verified by measurement:
/workspaceand/projare refused;/workspace/repo,/srv/xand/w/xindex fine.A fixed
/workspace/projectwas chosen over a dynamic/workspace/$(basename $PWD)becauseclaude-config.jsonandinstall-mcp-servers.shwrite configuration under a static project key that Claude Code looks up by working directory. A fixed path keeps all baked configuration baked, needs no new entrypoint logic, and works identically in all four entrypoints — including the Dev Container anddebug-shell.sh, where the image ENTRYPOINT never runs.All four entrypoints (
run_claude.sh,debug-shell.sh, theclaude-boxlauncher generated byinstall.sh, and the Dev Container) move together with the project key inclaude-config.json/install-mcp-servers.sh/diagnose-mcp.sh.Dependency bumps
@anthropic-ai/claude-code@fission-ai/openspecpnpmeslintLockfile regenerated inside
node:22(lockfileVersion3); the previously patchedform-data/hono/ip-addressversions were verified to survive the regeneration.typescriptstays at 6.0.3 — 7.x still breaksts-node10.9.2.npm auditre-derived rather than carried over: 2 high, and both rows are the same single advisory GHSA-w48q-cv73-mx4w (<1.24.0) reached throughperplexity-mcp— one row for the SDK, one for the dependent package. No fix available; still an accepted residual, andperplexity-mcpruns as a stdio server here with no listening socket. The previous wording (two distinct advisories, bound≤1.25.1) did not match the current output and has been corrected.caveman is deliberately held at v1.9.1
v2.2.0 adds a runtime dependency
@caveman-ai/cli: ^1.1.0, which ships its owncavemanbin. That bin shadows the installer's own bin undernpx, sonpx -y github:JuliusBrussee/caveman#v2.2.0 --non-interactive …never reachesbin/install.js— it runs the cloud CLI, which answersunknown command "--non-interactive". The installer script itself still accepts the old flags; it is simply unreachable that way.Independently of the invocation, that dependency is a floating range in a build layer (against this image's exact-pin policy), and
@caveman-ai/cliis an account/cloud CLI whose compression runs in "companion Go binaries" fetched bycaveman setup— a runtime download this image forbids. v1.9.1 has no dependencies at all. The reasoning is recorded in theDockerfileandCLAUDE.mdso a future bump starts from evidence rather than from scratch.codebase-memory-mcp hardening
CBM_ALLOWED_ROOT=/workspaceis now baked in. This was previously impossible because the ACP adapter mounted the project at its host-absolute path. Verified as a live control, not a dead knob: indexing/home/agentis refused withis outside the allowed root, while/workspace/projectindexes normally.config set ui_enabled false). Upstream defaultsui_enabledto true, so the coordination daemon otherwise binds127.0.0.1:9749on the first MCP session — contrary to the upstream README, which documents the UI as needing an explicit--ui=true --port=9749. A hardened image should not carry an undocumented listening socket, the less so becausePOST /api/indexon it drives indexing. Verified: no listening socket in/proc/net/tcpand noui.servingline in the daemon log.--pids-limit=100, soauto_watchis left at its default. Idle CPU spikes to ~100% of one core at daemon start, then settles at 2.1–2.4% (v0.9.0: 0.01–0.03%) — see open upstream issue #1764, whose severe form is reported on Windows.Add the cloudflare-docs MCP server
type: http, no API key, no headers, no npm package — nothing to pre-install and nothing to add to.env. Added to the third-party egress enumerations in bothREADME.md("Honest scope") andSECURITY.md("Outbound network is allowed"), since those name every service that receives code context.Documentation
README.md,CLAUDE.mdandSECURITY.mdupdated throughout: the ACP sections removed, versions and paths corrected, and every measured number re-derived on the built image rather than carried over.Two pre-existing drifts were fixed along the way:
CLAUDE.mdclaimed OpenSpec is initialized into the project mount; the Dockerfile initializes it into the build HOME (/home/claude).CLAUDE.mdclaimed caveman mergesSessionStart/UserPromptSubmithooks intosettings.json. Measured in the built image: those arrays are empty andPreToolUseholds only RTK'srtk hook claude— the hooks come from the plugin manifest, and the caveman layer does not clobber RTK's hook.A dead
permissions.additionalDirectoriesarray pointing at/workspace/{input,output,data,temp}was dropped rather than carried forward to the new path — those directories have not existed since the container moved to single read-write mode.Verification
Performed against the built image (
--cap-drop=ALL,--security-opt=no-new-privileges,--pids-limit=100, tmpfs HOME, host uid), not by reading code:--no-cachebuild green; bothsha256sum -cchecks pass for RTK v0.45.0 and codebase-memory-mcp v0.10.8./home/claude/start-acp.sh, noclaude-agent-acpon PATH, noCLAUDE_CODE_EXECUTABLE, no@agentclientprotocolin/opt/toolchain.claude mcp list→ all six servers✔ Connectedin ~5.7 s under the defaultMCP_TIMEOUT=10000.index_repositoryon/workspace/project→ 231 nodes / 279 edges, 2.3 MB cache; on/home/agent→ refused./proc/net/tcpand/proc/net/tcp6→ no listening sockets.codebase-memory-mcpMCP surface measured viatools/list: 15 tools (up from 8 in v0.9.0).PreToolUse=rtk hook claude,statusLinepresent, nocaveman-shrinkMCP entry./workspace/project,claude --version→ 2.1.238.claude doctoron 2.1.238: "No installation issues found." (only the expected Remote Control full-scope-token note)./app/diagnose-mcp.sh: 5 stdio binaries found, 6mcpServerskeys includingcloudflare-docs.\bacp\b|\bzed\b|agentclientprotocol|claude-agent-acp|claude-agent-sdk|start-acp|run_acp|CLAUDE_CODE_EXECUTABLE|ACP_PIDS_LIMIT→ only the deliberate historical mentions in theSECURITY.mdclosure note and theCLAUDE.mdexplanation of whyCBM_ALLOWED_ROOTbecame possible.Not verified here: arm64. The second sha256 pair of each GitHub-release binary is only exercised by the arm64 CI job on this PR.