fn agent_home_mounts(
container_name: &str,
spec: &ContainerMountSpec,
) -> Vec<Mount>Expand description
The mounts that make up the agent’s home dir inside the container.
The per-agent named volume stays mounted at CONTAINER_CLAUDE_DIR exactly
as before, and a bound account contributes ONE extra mount: its
.credentials.json, bind-mounted as a single file on top of that volume.
Binding the account’s whole config dir over …/.claude would be the more
obvious shape, and it does NOT work — both failures verified live on
2026-09-02 against ghcr.io/agentmuxai/agent-claude:latest:
- That dir’s
projectsentry is a symlink into the shared identities tree, which does not resolve in-container (ls→ “No such file or directory”). - Shadowing it with a nested volume at
…/.claude/projectsSILENTLY does not mount — Docker will not mount over a path that is a symlink inside a bind mount.mountshows only the parent 9p bind, and the CLI is left writing session state through the broken link. Chowning does not help; there is nothing there to chown.
Keeping the volume and binding just the credential file avoids both, and
preserves the existing ownership story: the volume is initialised from the
image, so projects/sessions stay writable by uid 1000. Verified end to
end — a container agent using this shape completed a real turn against the
bound account ("result":"AUTH_OK", is_error: false).
Known limitation — HOST UID PARITY. A bind preserves the host file’s owner
and mode (.credentials.json is typically 0600), while the image always
execs as agent, uid 1000. On a host whose AgentMux user is not uid 1000,
the container cannot read the token and authentication stays broken there.
That is deliberately NOT worked around here. It is the container design’s
pre-existing, documented assumption — “agent non-root user (UID 1000) …
Host filesystem UID parity” (SPEC_CONTAINER_PANE_SUPPORT_2026_06_11.md §
“What claw’s containers provide”; the Dockerfile renames node:22-slim’s
uid-1000 user for exactly this) — and the /workspace bind below has the
identical problem: at uid != 1000 the agent cannot write its own workspace
either. Special-casing credentials would fix one symptom of that assumption
and leave the other, while adding a second provisioning path to maintain.
The real fix is to exec as the host uid/gid, which is an architectural change
affecting every mount, and belongs in its own PR.
Known limitation: a single-file bind follows the inode. If the CLI ever
replaces .credentials.json by atomic rename rather than writing in place, a
refreshed token would land on the host but not be seen by the running
container until it is recreated. Reads — the case that was totally broken —
are unaffected.