NanoClaw runs agents in isolated Linux containers to provide security through OS-level process and filesystem isolation. In v2, the container runtime uses a two-database IO model instead of stdin/stdout piping, and the agent-runner runs on Bun instead of Node.js.Documentation Index
Fetch the complete documentation index at: https://docs.nanoclaw.dev/llms.txt
Use this file to discover all available pages before exploring further.
Runtime abstraction
All runtime-specific logic lives insrc/container-runtime.ts:
- Docker (default) — cross-platform support (macOS, Linux, Windows via WSL2)
- Apple Container (macOS only) — lightweight native runtime
CONTAINER_RUNTIME_BIN:
Apple Container vs Docker
Apple Container is Apple’s native virtualization framework (macOS 15+). It runs Linux containers without a VM layer like Docker Desktop.When to use Apple Container
- You’re on macOS 15 (Sequoia) or later
- You want to avoid installing Docker Desktop
- You want faster container startup
When to stick with Docker
- You’re on Linux or Windows (WSL2)
- You need cross-platform parity
- You’re deploying to a production server
Key differences
| Docker | Apple Container | |
|---|---|---|
| Binary | docker | container |
| Bind mounts | -v host:container:ro | --mount type=bind,source=...,target=...,readonly |
| Stop command | docker stop -t 1 name | container stop name |
| Health check | docker info | container system status |
| Platform | macOS, Linux, Windows (WSL2) | macOS 15+ only |
Switching runtimes
Run the/convert-to-apple-container skill in Claude Code. To revert, use git revert.
Container image
The agent container is built fromcontainer/Dockerfile and includes:
- Node.js 22 — base image runtime
- Bun (pinned to 1.3.12) — runs agent-runner TypeScript directly (no compilation)
- Chromium — browser automation via agent-browser
- Claude Code SDK —
@anthropic-ai/claude-codeinstalled globally via pnpm - tini — PID 1 signal forwarding (ensures outbound.db writes finalize on SIGTERM)
- pnpm (via corepack) — for global Node CLI installs
- System tools —
curl,git,ca-certificates,unzip - Optional CJK fonts —
fonts-noto-cjk(~200 MB, opt-in viaINSTALL_CJK_FONTS=true)
Key design decisions
- Source is NOT baked in —
/app/srcis a read-only bind mount from the host. Source changes never require an image rebuild. only-built-dependenciesallowlist in.npmrcforagent-browserand@anthropic-ai/claude-code- Runs as
nodeuser (non-root) with/workspace/groupas working directory - Entrypoint:
tini -> entrypoint.sh -> exec bun run /app/src/index.ts
Building the image
Per-agent-group images
Agent groups can specify custom packages incontainer.json. The host builds a derived Docker image:
- Tag: derived from the checkout-scoped base image and agent group
- Built on top of
nanoclaw-agent-v2-<slug>:latest - Adds custom apt and npm packages
Two-database IO model
In v2, all communication between host and container uses two SQLite databases per session. There is no stdin/stdout piping, no IPC files, and no output markers.inbound.db (host writes, container reads)
| Table | Purpose |
|---|---|
messages_in | Inbound messages, tasks, system notifications |
delivered | Tracks delivery outcomes for outbound message IDs |
destinations | Live destination map (channels and other agents) |
session_routing | Default reply routing (channel_type, platform_id, thread_id) |
outbound.db (container writes, host reads)
| Table | Purpose |
|---|---|
messages_out | Outbound messages with deliver_after and recurrence |
processing_ack | Tracks which inbound messages the container has processed |
session_state | Persistent key/value store (e.g., SDK session ID for resume) |
container_state | Tool-in-flight state for stuck-detection |
Cross-mount invariants
Three invariants are critical for correctness:journal_mode=DELETE— WAL’s mmapped-shmdoesn’t refresh across Docker mounts- Host opens-writes-closes per operation — closing invalidates the container’s page cache
- One writer per file — DELETE-mode journal unlink isn’t atomic across the mount
Container lifecycle
Spawning containers
Containers are spawned by thespawnContainer function. Wake calls are deduplicated via an in-flight promise map.
Build volume mounts
Mounts are built based on the session, agent group, and validated additional mounts.
Sync skill symlinks
Skill symlinks at
/home/node/.claude/skills/ are updated to point to /app/skills/{name}. These are dangling on the host but valid inside the container.Volume mounts
| Path | Container path | Mode | Purpose |
|---|---|---|---|
| Session folder | /workspace | RW | inbound.db, outbound.db, outbox/, inbox/ |
| Agent group folder | /workspace/agent | RW | Working files |
| container.json | /workspace/agent/container.json | RO | Nested read-only config |
| Composed CLAUDE.md | /workspace/agent/CLAUDE.md | RO | Regenerated each spawn |
| Global memory | /workspace/global | RO | Shared instructions |
| Agent-runner source | /app/src | RO | Bind mount from host |
| Container skills | /app/skills | RO | Shared skill definitions |
| Claude SDK state | /home/node/.claude | RW | SDK state + skill symlinks |
| Additional mounts | /workspace/extra/{name} | Per-config | Validated against allowlist |
| Provider mounts | Various | Per-provider | Provider-contributed |
Timeouts and stale detection
Containers have two timeout/detection mechanisms:- Container timeout — maximum runtime before force kill (default: 30 minutes)
- Stale detection — host sweep checks
.heartbeatmtime andprocessing_ackage to detect stuck containers
Container shutdown
killContainer(sessionId, reason)stops the container viadocker stop, falls back to SIGKILL- On close/error, the session is marked stopped and typing indicators are cleared
Credential injection
The OneCLI SDK’sapplyContainerConfig() configures each container’s network to route through the vault:
- Injects
HTTPS_PROXYand CA certs into Docker args - All container API calls route through the vault
- No raw API keys are passed via environment variables
- Each agent group gets its own
agentIdentifierfor credential scoping
Debugging containers
List running containers
List running containers
View container logs
View container logs
Inspect container mounts
Inspect container mounts
Execute commands in running container
Execute commands in running container
Stop a running container
Stop a running container
Related pages
- Security model — container isolation and security boundaries
- Troubleshooting — common container issues