docker run. Every container goes through a multi-phase initialization that sets up workspace mirroring, git integration, session persistence, credential forwarding, and security controls. This page explains what happens under the hood and why.
Container Lifecycle
When you runclawker run @ or clawker container create @, the container goes through four phases before it’s ready:
- Workspace — resolve the working directory, set up mounts, ensure volumes
- Config — initialize the Claude Code config volume (first run only)
- Environment — start the host proxy, forward git credentials, resolve environment variables
- Container — validate flags, build Docker configs, create the container, inject post-init scripts
Create vs Start vs Run
| Command | What it does |
|---|---|
clawker container create | Runs all four init phases, produces a stopped container |
clawker container start | Starts an existing container (no init, attaches if interactive) |
clawker run | Create + Start in one step |
Workspace Mounting
The most important mount is the workspace — your project source code made available inside the container. Clawker supports two workspace modes:Bind Mode (default)
Your host directory is mounted directly into the container as a live bind mount. Changes on either side are visible immediately. This is the default because it gives Claude Code real-time access to your latest code.Snapshot Mode
A one-time copy of your project is placed into a Docker volume. The container works on an isolated snapshot — changes inside the container don’t affect your host, and vice versa. Useful when you want Claude to experiment without risk.Path Mirroring
Here’s something subtle but important: the workspace is not mounted at a generic path like/workspace. Instead, Clawker mirrors your host’s actual directory structure inside the container.
If your project lives at /Users/schmitthub/Code/myapp on the host, it appears at /Users/schmitthub/Code/myapp inside the container too. The container’s working directory is set to match.
Why? Claude Code tracks sessions by the current working directory. When you use /resume to pick up a previous conversation, it discovers your project’s git worktrees and looks for session files that match those paths. If the container used a synthetic path like /workspace, those session lookups would fail — the paths wouldn’t match what git reports, and Claude Code would say “No conversations found.”
By mirroring the real host path, everything lines up naturally: sessions created in the container are findable by /resume.
Git Integration
Clawker makes git work seamlessly inside containers, even for advanced setups like worktrees.Standard Repositories
For a normal (non-worktree) project, the.git directory is part of your workspace and gets mounted along with everything else. Git commands inside the container work exactly as they do on your host.
Worktree Support
Git worktrees are more complex. A worktree is a separate checkout of your repository that shares the same.git metadata as the main repo. The worktree directory contains a .git file (not a directory) that points back to the main repository’s .git/worktrees/<name>/ metadata.
The challenge: those .git file references use absolute host paths. If the main repo is at /Users/schmitthub/Code/myapp, the worktree’s .git file says something like:
.git directory at its original absolute path inside the container. The mount source and target are identical — if the .git directory lives at /Users/schmitthub/Code/myapp/.git on the host, it appears at exactly that path in the container.
Combined with path mirroring for the worktree directory itself, git commands work correctly: the .git file’s reference resolves, git finds the shared metadata, and operations like git log, git status, and git commit all behave normally.
Credential Forwarding
Git credentials are forwarded into the container automatically based on your project’s security settings:- HTTPS — Clawker runs a host proxy that the container’s git credential helper calls through. Your host’s git credentials are never copied into the container.
- SSH — SSH agent forwarding is handled via a socket bridge (muxrpc over
docker exec). Your SSH keys stay on the host. - GPG — GPG agent forwarding works the same way as SSH, via the socket bridge.
- Git config — Your
~/.gitconfigis bind-mounted read-only at/tmp/host-gitconfiginside the container. On startup, the entrypoint reads that file, filters out any[credential]sections, and writes the sanitized result to~/.gitconfiginside the container (which then uses its own credential forwarding).
Session Persistence
Claude Code sessions are preserved across container restarts through persistent Docker volumes.Config Volume
Each agent gets a dedicated config volume (namedclawker.<project>.<agent>-config) mounted at ~/.claude inside the container. This volume stores:
- Session transcripts — Full conversation history as JSONL files under
projects/<mangled-cwd>/(where the directory name is derived from the working directory path, with non-alphanumeric characters replaced by hyphens) - Config state — The
.config.jsonfile tracking the last session ID, startup count, and project metadata - Plugins and settings — Any Claude Code plugins or settings that persist across sessions
History Volume
A second volume (clawker.<project>.<agent>-history) preserves shell command history at /commandhistory, so your bash history carries over between sessions.
How Resume Works
When you type/resume inside Claude Code, it needs to find previous sessions for the current project. Here’s the discovery process:
- Claude Code reads the
.gitmetadata in the current working directory - It discovers all git worktrees associated with the repository (the main checkout plus any worktrees)
- For each worktree path, it looks for session files stored under that path’s identifier
- It presents matching sessions for you to resume
/workspace as its working directory, Claude Code would store sessions under a /workspace identifier, but the worktree discovery step would return host-absolute paths. The identifiers wouldn’t match, and resume would find nothing.
With path mirroring:
- Container cwd =
/Users/schmitthub/Code/myapp(matches the host) - Sessions stored under the
/Users/schmitthub/Code/myappidentifier - Git worktree discovery returns
/Users/schmitthub/Code/myappin its list /resumefinds the sessions
/resume.
First-Run Initialization
The first time a container is created for a given project+agent combination, Clawker initializes the config volume:- Onboarding bypass — The container image includes a seed config that marks onboarding as complete, so Claude Code doesn’t show the first-run wizard
- Host config copy — If
agent.claude_code.config.strategyis set tocopy(the default), your host’s Claude Code plugin configuration, installed plugins, agents, skills, and custom commands are copied into the config volume - Credential injection — If
agent.claude_code.use_host_authis enabled, your host’s Claude Code credentials are copied so the container can authenticate without re-login
Post-Init Scripts
If yourclawker.yaml includes a post_init script, it’s injected into the container after creation and runs once on first start. A marker file prevents it from running again on restarts. This is useful for project-specific setup like installing dependencies or configuring tools.
Volumes and Naming
Clawker uses a consistent naming scheme for all Docker resources:| Resource | Pattern | Example |
|---|---|---|
| Container | clawker.<project>.<agent> | clawker.myapp.dev |
| Config volume | clawker.<project>.<agent>-config | clawker.myapp.dev-config |
| History volume | clawker.<project>.<agent>-history | clawker.myapp.dev-history |
| Workspace volume | clawker.<project>.<agent>-workspace | clawker.myapp.dev-workspace (snapshot mode only) |
dev.clawker.project, dev.clawker.agent) for filtering and management. The clawker container ls command uses these labels to show only Clawker-managed containers.
Volume Lifecycle
- Config and history volumes persist independently of containers. Removing a container does not remove its volumes. Use
clawker volume pruneto clean up orphaned volumes. - Workspace volumes (snapshot mode only) are ephemeral and tied to the container lifecycle.
- Volume cleanup on failure — If container creation fails partway through, only volumes created during that attempt are cleaned up. Pre-existing volumes with your session data are never touched.
Container Image
Clawker builds custom Docker images tailored to your project. The image includes:- A base image (default:
buildpack-deps:bookworm-scm) - System packages you’ve specified (
build.packages) - Claude Code (installed via npm)
- An agent awareness prompt at
/etc/claude-code/CLAUDE.md - An entrypoint script that handles init, firewall readiness, and privilege drop
- Firewall and credential helper scripts
- A non-root user (
claude) with sudo access
Agent Awareness Prompt
Every Clawker image includes a prompt file baked in at/etc/claude-code/CLAUDE.md. Claude Code automatically loads this file, giving the agent awareness of its containerized environment without any user configuration.
The prompt tells the agent:
- What it can do — read/write workspace files, run commands, install packages, use git (credentials forwarded from host)
- What it cannot do — modify firewall rules, access the host filesystem outside the workspace, manage other containers
- How the firewall works — DNS queries for unlisted domains return NXDOMAIN, connection failures mean the domain isn’t allowlisted
- How to help the user — when the agent hits a blocked domain, it explains the problem and suggests the correct
clawker firewall add,clawker firewall bypass, orclawker firewall disablecommand for the user to run on the host - Environment diagnostics — lists environment variables (
CLAWKER_PROJECT,CLAWKER_AGENT,CLAWKER_WORKSPACE_MODE,CLAWKER_FIREWALL_ENABLED, etc.) the agent can inspect for troubleshooting
Entrypoint
The entrypoint script (entrypoint.sh) runs as root on every container start. It performs initialization, then drops privileges to the claude user before launching the main process. All output is suppressed except for structured progress signals — a spinner shows each step in TTY mode, plain log lines in non-TTY mode.
Initialization Steps
-
Firewall readiness (if
CLAWKER_FIREWALL_ENABLED=true) — The entrypoint waits for the host-side firewall manager to apply iptables rules inside the container. The manager runsfirewall.sh enableviadocker execafter the container starts, then touches a signal file. The entrypoint polls for this file with a 30-second timeout. This ensures the agent’s first network request goes through the firewall, not around it. -
Config seeding — If the config volume (
~/.claude) doesn’t have a.config.json, the entrypoint seeds it from the image’s init directory. This bypasses Claude Code’s first-run onboarding wizard. Thesettings.jsonis merged: image defaults first, then any existing user settings override. -
Git config — Copies the host’s
.gitconfig(bind-mounted at/tmp/host-gitconfig) into the container, filtering out[credential]sections so the container uses Clawker’s forwarded credential helpers instead of host-side stores that don’t exist in the container. -
Git credential helper — If HTTPS forwarding is enabled (
CLAWKER_HOST_PROXYset +CLAWKER_GIT_HTTPS=true), configuresgit-credential-clawkeras the global credential helper. -
SSH known hosts — Unconditionally adds GitHub, GitLab, and Bitbucket SSH host keys to
~/.ssh/known_hosts. This runs regardless of credential forwarding settings because SSH operations need known hosts even without agent forwarding. -
Post-init script — If
agent.post_initis configured and hasn’t been run yet (tracked by a marker file on the config volume), executes it as the container user. Failure aborts startup. The marker persists across container recreations — to re-run, delete~/.claude/post-initializedor the config volume. -
Privilege drop + exec — Signals readiness, restores stdout/stderr, and execs
gosu claude <command>(default:claude).
Firewall Decoupling
The firewall is intentionally not configured by the entrypoint. Instead:- The container starts with default network connectivity
- The host-side firewall manager execs
firewall.sh enableinto the running container, which configures iptables DNAT rules to redirect traffic through Envoy and DNS queries through CoreDNS - The manager touches
/var/run/clawker/firewall-readyas a signal - The entrypoint unblocks and proceeds with user-level init
Shared Directory
Whenagent.enable_shared_dir is set to true, Clawker mounts a shared directory from ~/.local/share/clawker/share/ on the host into the container at ~/.clawker-share (read-only). This lets you share files across all agents without including them in the workspace.
Security Controls
Every container runs with a deny-by-default network firewall. See Security for the full details on:- The bare-bones hardcoded allowlist and why you must configure your own domains
- Docker socket access
- Linux capabilities
- Agent awareness prompt
- Credential isolation