Part of #2
D5 — Bind-mount contract for agent CLIs
Labels: wayfinder:grilling status:closed
Blocks: D6, D8
Resolution
Hybrid contract: image ships a curated baked-in agent set AND supports an /opt/agents bind-mount for operator extensions/overrides. Specific baked set is deferred to D9 — Curated baked-agent set; this ticket locks the shape.
Spec fragment:
- Base image:
debian:stable-slim (not alpine — musl breaks glibc-linked host binaries bind-mounted in, and rules out common precompiled tools).
- Pre-installed runtimes & tools:
nodejs (current LTS via NodeSource) + npm
python3 + pip3
git
ca-certificates
coreutils (already in debian-slim)
su-exec or gosu (from D4)
tini (from D4/D6, for PID-1 reap)
- Skip: rust, go, ruby, php, jvm — out of scope for v1.
- Baked agent install location:
/usr/local/bin (npm globals land here by default; pip --prefix=/usr/local). No dedicated directory.
- Bind-mount extension point:
/opt/agents — image creates the empty dir. Operators mount their own binaries here (-v ~/.local/bin:/opt/agents:ro or curated dir).
- PATH order:
PATH=/opt/agents:/usr/local/bin:/usr/bin:/bin (image ENV). Operator's bind-mounted binaries shadow the baked ones — this is deliberate: it's how users pin an agent to a specific host-installed version if a baked one breaks.
- HydratePATH: image sets
CHARTR_NO_PATH_PROBE=1. In-container there's no operator login-shell to inherit from; the probe would waste ~200ms on a guaranteed no-op. The existing gate (internal/env/path.go:48) already supports this — zero Go change.
- Agent auth material: two supported patterns, both demonstrated in D8's compose example:
- Bind-mount host state: e.g.
-v ~/.claude:/config/agents/.claude:ro (readonly if the agent only reads; writable if it needs to persist).
- Env passthrough via compose
env_file: for API keys (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.).
- Known-broken shape (troubleshooting doc entry, not a code change): agent CLIs that hardcode
$HOME-relative paths outside of ~/.claude, ~/.config, or their own dotfile — operator must bind-mount whatever the CLI needs. This is a documentation surface, not an image concern.
Downstream impact:
- Destination Notes update — the "thin runtime, not batteries-included" line no longer holds; the map Notes will be reworded to "curated baked-in agent set with a bind-mount extension point."
- D6 (Dockerfile) — install steps (nodejs LTS, python3, git);
ENV PATH=/opt/agents:..., ENV CHARTR_NO_PATH_PROBE=1; RUN mkdir /opt/agents; agent install steps come from D9.
- D7 (GHCR workflow) — image is larger; note in buildx cache strategy that node/python layer changes rarely, so cache hit rate stays high.
- D8 (compose + docs) — show BOTH auth patterns; show optional
/opt/agents bind-mount example.
- New fog — "one image or
chartr:slim + chartr:latest variants" — deferred; may graduate once D9 nails the baked set size.
Question
The image is a thin runtime; agent CLIs (Claude Code, Codex, aider, etc.) come from the host via bind-mount. Decide the contract:
- What exactly does the operator mount? A single
bin/ directory prepended to PATH? Individual binaries? The host's ~/.local/bin?
- Does the image need any runtime dependencies pre-installed so bind-mounted CLIs actually run (node? python? glibc vs musl compatibility of a debian-slim vs. alpine base)?
- How does chartr's agent registration inside the container find these binaries — hardcoded PATH prefix, or a
CHARTR_AGENTS_DIR env pointing at the mount?
- What breaks if a user's CLI is a shell script depending on host-side files (e.g. references
~/.config/... inside its own script)? Document known-good vs. known-broken shapes.
- Contract for auth material the agent CLI needs (e.g.
~/.claude, API keys) — bind-mount, env passthrough, or out of scope for this ticket and lives in the compose example (D8)?
Deliverable: a short "agent bind-mount contract" spec fragment + list of pre-installed runtime deps the base image must include.
Part of #2
D5 — Bind-mount contract for agent CLIs
Labels:
wayfinder:grillingstatus:closedBlocks: D6, D8
Resolution
Hybrid contract: image ships a curated baked-in agent set AND supports an
/opt/agentsbind-mount for operator extensions/overrides. Specific baked set is deferred to D9 — Curated baked-agent set; this ticket locks the shape.Spec fragment:
debian:stable-slim(not alpine — musl breaks glibc-linked host binaries bind-mounted in, and rules out common precompiled tools).nodejs(current LTS via NodeSource) +npmpython3+pip3gitca-certificatescoreutils(already in debian-slim)su-execorgosu(from D4)tini(from D4/D6, for PID-1 reap)/usr/local/bin(npm globals land here by default; pip--prefix=/usr/local). No dedicated directory./opt/agents— image creates the empty dir. Operators mount their own binaries here (-v ~/.local/bin:/opt/agents:roor curated dir).PATH=/opt/agents:/usr/local/bin:/usr/bin:/bin(imageENV). Operator's bind-mounted binaries shadow the baked ones — this is deliberate: it's how users pin an agent to a specific host-installed version if a baked one breaks.CHARTR_NO_PATH_PROBE=1. In-container there's no operator login-shell to inherit from; the probe would waste ~200ms on a guaranteed no-op. The existing gate (internal/env/path.go:48) already supports this — zero Go change.-v ~/.claude:/config/agents/.claude:ro(readonly if the agent only reads; writable if it needs to persist).env_file:for API keys (ANTHROPIC_API_KEY,OPENAI_API_KEY, etc.).$HOME-relative paths outside of~/.claude,~/.config, or their own dotfile — operator must bind-mount whatever the CLI needs. This is a documentation surface, not an image concern.Downstream impact:
ENV PATH=/opt/agents:...,ENV CHARTR_NO_PATH_PROBE=1;RUN mkdir /opt/agents; agent install steps come from D9./opt/agentsbind-mount example.chartr:slim+chartr:latestvariants" — deferred; may graduate once D9 nails the baked set size.Question
The image is a thin runtime; agent CLIs (Claude Code, Codex, aider, etc.) come from the host via bind-mount. Decide the contract:
bin/directory prepended toPATH? Individual binaries? The host's~/.local/bin?CHARTR_AGENTS_DIRenv pointing at the mount?~/.config/...inside its own script)? Document known-good vs. known-broken shapes.~/.claude, API keys) — bind-mount, env passthrough, or out of scope for this ticket and lives in the compose example (D8)?Deliverable: a short "agent bind-mount contract" spec fragment + list of pre-installed runtime deps the base image must include.