[feat] All-harness self-hostable agent sidecar (Claude Code + Pi)#4880
[feat] All-harness self-hostable agent sidecar (Claude Code + Pi)#4880mmabrouk wants to merge 1 commit into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Draft, do-not-merge. Code review needed on three specific things:
Not a functionality/UX check — nothing is wired into the app. CodeRabbit will run once this is marked ready; left as draft per the task. |
There was a problem hiding this comment.
Actionable comments posted: 3
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: dbcfa6ae-bb6a-402e-b72e-d3632583d372
📒 Files selected for processing (5)
docs/design/agent-workflows/projects/sidecar-deployment-proposal/status.mddocs/design/agent-workflows/projects/subscription-sidecar/README.mdservices/agent/docker/Dockerfile.sidecarservices/agent/docker/README.mdservices/agent/docker/sidecar-entrypoint.sh
| FROM ${RUNNER_IMAGE} | ||
|
|
||
| # Re-declare after FROM so the ARG is in scope for the RUN below. | ||
| ARG INSTALL_CLAUDE_CODE=true |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== Dockerfile.sidecar relevant lines ==\n'
sed -n '1,180p' services/agent/docker/Dockerfile.sidecar | nl -ba | sed -n '70,120p'
printf '\n== Search for INSTALL_CLAUDE_CODE usage ==\n'
rg -n "INSTALL_CLAUDE_CODE|Claude Code|redistribut|non-redistribut" services/agent/docker services/agent -S
printf '\n== Find related Dockerfiles / docs ==\n'
fd -a -t f "Dockerfile*" services/agent/dockerRepository: Agenta-AI/agenta
Length of output: 235
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== Dockerfile.sidecar lines 70-120 ==\n'
awk 'NR>=70 && NR<=120 { printf "%4d %s\n", NR, $0 }' services/agent/docker/Dockerfile.sidecar
printf '\n== Search for INSTALL_CLAUDE_CODE usage ==\n'
rg -n "INSTALL_CLAUDE_CODE|Claude Code|redistribut|non-redistribut" services/agent/docker services/agent -S
printf '\n== Dockerfiles under services/agent/docker ==\n'
fd -a -t f "Dockerfile*" services/agent/dockerRepository: Agenta-AI/agenta
Length of output: 12628
Make the Claude-baked image opt-in.
INSTALL_CLAUDE_CODE=true makes a plain build produce the non-redistributable variant. Flip the default to false and opt in explicitly when you need the baked image.
|
|
||
| # Idempotent: /pi-agent is pre-created and owned by the runtime user at image build. This | ||
| # only matters if PI_CODING_AGENT_DIR was overridden to a fresh, writable path. | ||
| mkdir -p "$PI_DIR" 2>/dev/null || true |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Fail fast when PI_CODING_AGENT_DIR is not writable.
Silencing mkdir errors here lets the container boot and only fail later when the runner tries to install the Pi extension. If this directory cannot be created or written, startup should stop immediately.
Suggested change
-mkdir -p "$PI_DIR" 2>/dev/null || true
+mkdir -p "$PI_DIR"
+[ -w "$PI_DIR" ] || {
+ echo "PI_CODING_AGENT_DIR is not writable: $PI_DIR" >&2
+ exit 1
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| mkdir -p "$PI_DIR" 2>/dev/null || true | |
| mkdir -p "$PI_DIR" | |
| [ -w "$PI_DIR" ] || { | |
| echo "PI_CODING_AGENT_DIR is not writable: $PI_DIR" >&2 | |
| exit 1 | |
| } |
| if [ -d /pi-agent-ro ]; then | ||
| cp -a /pi-agent-ro/. "$PI_DIR"/ 2>/dev/null || true |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Seed once without overwriting existing Pi state.
cp -a will overwrite files on every restart. If $PI_DIR is persisted, a stale /pi-agent-ro seed can roll back newer login/session data and extension state. This should be a no-clobber seed, not a resync.
Suggested change
if [ -d /pi-agent-ro ]; then
- cp -a /pi-agent-ro/. "$PI_DIR"/ 2>/dev/null || true
+ cp -an /pi-agent-ro/. "$PI_DIR"/
fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if [ -d /pi-agent-ro ]; then | |
| cp -a /pi-agent-ro/. "$PI_DIR"/ 2>/dev/null || true | |
| if [ -d /pi-agent-ro ]; then | |
| cp -an /pi-agent-ro/. "$PI_DIR"/ | |
| fi |
97b95ef to
2d4eb44
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
services/agent/docker/README.md (1)
99-106: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winLicensing boundary wording is careful, but the
truedefault is a foot-gun.The explanation correctly distinguishes recipe from published image and warns against redistribution. However, since
INSTALL_CLAUDE_CODE=trueis the default, a self-hoster who misses the warning builds a non-redistributable image. Consider adding a bold warning at the top of the build instructions (Line 108) or in the bullet on Line 9, or flipping the default tofalseas the author noted is a one-line change. The current docs are legally defensible; making the safe path the default would be more robust.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: d0e875ff-9141-4d5f-9401-08dd8b0133a5
📒 Files selected for processing (5)
docs/design/agent-workflows/projects/sidecar-deployment-proposal/status.mddocs/design/agent-workflows/projects/subscription-sidecar/README.mdservices/agent/docker/Dockerfile.sidecarservices/agent/docker/README.mdservices/agent/docker/sidecar-entrypoint.sh
✅ Files skipped from review due to trivial changes (3)
- services/agent/docker/sidecar-entrypoint.sh
- docs/design/agent-workflows/projects/subscription-sidecar/README.md
- docs/design/agent-workflows/projects/sidecar-deployment-proposal/status.md
🚧 Files skipped from review as they are similar to previous changes (1)
- services/agent/docker/Dockerfile.sidecar
| `pi_agenta`, and `claude`. Optionally bakes Claude Code from Anthropic for fast cold | ||
| starts. See [The all-harness self-host sidecar](#the-all-harness-self-host-sidecar) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
"Optionally bakes" contradicts the true default.
The bullet says "Optionally bakes Claude Code" but the default INSTALL_CLAUDE_CODE=true means it bakes unless explicitly disabled. Change to "Bakes Claude Code by default (disable with INSTALL_CLAUDE_CODE=false)" or similar to avoid implying opt-in when it's opt-out.
New Dockerfile.sidecar + sidecar-entrypoint.sh: one self-host image that serves every harness (pi_core, pi_agenta, claude) on :8765 with no compose CMD override. Builds on the production runner image and bakes the Pi provisioning the dev compose CMD does inline (a writable /pi-agent so the Agenta Pi extension installs without EACCES), gives Claude Code a writable HOME for the read-only ~/.claude OAuth mount, and optionally bakes Claude Code from Anthropic (INSTALL_CLAUDE_CODE, self-host licensing boundary documented). Docs synced in docker/README.md + the subscription-sidecar and sidecar-deployment-proposal project docs. Claude-Session: https://claude.ai/code/session_01GYo3UEfvsZpncagqb28Mbc
2d4eb44 to
7a48130
Compare
Context
We run a second agent-runner sidecar (
agenta-claude-sub-sidecar) that authenticates Claude Code with a subscription OAuth (a read-only~/.claudemount) instead of an API key. It is the same runner image as the mainsandbox-agent, but started with the plain default entrypoint, as a non-root user, with no Pi provisioning. The result: it can hostclaude, but every Pi run crashes withEACCES: mkdir '/pi-agent/extensions'.Why: the main runner only hosts Pi because the dev compose service overrides the image CMD — it runs as root, does
mkdir -p /pi-agent+ copies the Pi login + rebuilds the extension, then serves. A baredocker runof that image as a non-root user has no writablePI_CODING_AGENT_DIR, so the runner daemon cannot lay the Agenta Pi extension and fails. There was no single image a self-hoster coulddocker build+docker runthat serves every harness.This PR adds that image: a self-host recipe that bakes the Pi provisioning into the image (no compose CMD), keeps the
~/.claudeOAuth mount working, and serves all three harnesses (pi_core,pi_agenta,claude).What changed
services/agent/docker/Dockerfile.sidecar(new) —FROMthe production runner image (reuses that build, does not fork it). As root it creates/pi-agentowned by the runtime user (node) and, behindARG INSTALL_CLAUDE_CODE=true, installs Claude Code from Anthropic; then setsPI_CODING_AGENT_DIR=/pi-agent, a writableHOME=/home/node,AGENTA_AGENT_RUNNER_HOST=0.0.0.0,SANDBOX_AGENT_PROVIDER=local, drops toUSER node, and serves.services/agent/docker/sidecar-entrypoint.sh(new) — ensuresPI_CODING_AGENT_DIRand seeds an optional read-only Pi login mounted at/pi-agent-ro(the samecp -a /pi-agent-ro/.the compose CMD does), then execs the server. The Pi extension bundle is already indist/from the runner image'sbuild:extension, so there is no runtime rebuild.services/agent/docker/README.mdgains an "all-harness self-host sidecar" section (build + run + licensing boundary); thesubscription-sidecarproject README cross-links it as the productized form; thesidecar-deployment-proposalstatus logs it.Provisioning vs the old compose CMD
mkdir -p /pi-agentas root/pi-agentcreated at build, owned bynode(works non-root, noEACCES)cp -a /pi-agent-ro/.(Pi login seed)/pi-agent-roif mountednode scripts/build-extension.mjs(rebuild, src bind-mounted)dist/(src is baked, no rebuild)exec tsx src/server.tsENTRYPOINT+CMDserve asnodeScope / risk
services/agent/docker/DockerfileandDockerfile.dev, the compose stack, and the liveagenta-claude-sub-sidecarare untouched. Nothing wires this image into the app.INSTALL_CLAUDE_CODE=trueit installs Claude Code from Anthropic at build, so the self-hoster who runsdocker buildis the one pulling it for their own individual use. The resulting image must not be published/distributed by Agenta — that would make Agenta a Claude Code redistributor, which Anthropic's Commercial Terms forbid.--build-arg INSTALL_CLAUDE_CODE=falsegives a redistribution-safe base that installs Claude at runtime instead. No credential is ever baked.127.0.0.1(the runner trusts its caller with resolved secrets).node(uid 1000); on a host whose uid is not 1000 the read-only~/.claudemount may be unreadable — documented.How to QA
Prerequisites: Docker; a Claude subscription OAuth at
~/.claude/.credentials.json(token prefixsk-ant-oat01-) on a uid-1000 host, OR anANTHROPIC_API_KEY.docker run -d --name allharness-test -p 127.0.0.1:8791:8765 \ -v "$HOME/.claude":/home/node/.claude:ro agenta-allharness-sidecar:test curl -s http://127.0.0.1:8791/health{"status":"ok",...,"harnesses":["pi_core","claude","pi_agenta"]}.{"ok":true,...}.EACCES:{"ok":true,"output":"hi from pi",...}.docker rm -f allharness-test && docker rmi agenta-allharness-sidecar:test.Edge cases worth a look:
--build-arg INSTALL_CLAUDE_CODE=false(Claude installs at runtime on first run, ~10s); seeding a Pi login via-v "$HOME/.pi/agent":/pi-agent-ro:ro.Verified in isolation (this PR)
Built both images, ran a test container on
:8791with the~/.claudemount (the live:8790sidecar and the:8280stack untouched). Both harnesses passed: aclaude+haikusubscription-OAuth run returnedok:truein ~4.3s (no install delay -> baked Claude Code used), and api_core+claude-haiku-4-5run returnedok:truewith no/pi-agentEACCES and/pi-agent/extensions/agenta.jsinstalled. Test container and images removed afterward.https://claude.ai/code/session_01GYo3UEfvsZpncagqb28Mbc