Container execution architecture and runtime details
NanoClaw runs agents in isolated Linux containers to provide security through OS-level process and filesystem isolation. The container runtime is abstracted to support multiple backends.
Apple Container is Apple’s native virtualization framework (macOS 15+). It runs Linux containers without a VM layer like Docker Desktop, making it lighter weight and faster to start.
Run the /convert-to-apple-container skill in Claude Code:
Copy
Ask AI
/convert-to-apple-container
The skill modifies src/container-runtime.ts to change the binary from docker to container and adjusts mount syntax, stop commands, and health check commands accordingly. To revert, use git revert.
Apple Container uses the same container/Dockerfile to build the agent image. If you switch runtimes, rebuild the image with container build instead of docker build.
The slim Node.js base keeps the image small while providing the necessary runtime.
Browser configuration
Copy
Ask AI
# Set Chromium path for agent-browserENV AGENT_BROWSER_EXECUTABLE_PATH=/usr/bin/chromiumENV PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium# Install agent-browser and claude-code globallyRUN npm install -g agent-browser @anthropic-ai/claude-code
Browser automation is available to all agents via the agent-browser command.
Agent runner compilation
Copy
Ask AI
# Copy package files first for better cachingCOPY agent-runner/package*.json ./RUN npm install# Copy source codeCOPY agent-runner/ ./RUN npm run build
The agent runner is pre-built during image creation for faster startup.
Workspace setup
Copy
Ask AI
# Create workspace directoriesRUN mkdir -p /workspace/group /workspace/global /workspace/extra \ /workspace/ipc/messages /workspace/ipc/tasks /workspace/ipc/input# Set ownership to node user (non-root) for writable directoriesRUN chown -R node:node /workspace && chmod 777 /home/node# Switch to non-root userUSER node# Set working directory to group workspaceWORKDIR /workspace/group
Containers run as the unprivileged node user (uid 1000) for security.
Rebuild the container image after modifying the Dockerfile or agent-runner:
Copy
Ask AI
./container/build.sh
The container buildkit caches the build context aggressively. --no-cache alone does NOT invalidate COPY steps. To force a clean rebuild, prune the builder:
The input JSON contains the prompt, session ID, group folder, and metadata. Credentials are handled by the secret injection layer (OneCLI gateway or credential proxy) — never passed via stdin or mounted as files.
5
Stream output
The host parses output markers (---NANOCLAW_OUTPUT_START--- and ---NANOCLAW_OUTPUT_END---) from stdout and calls the onOutput callback for each complete message.
6
Handle completion
When the container exits, logs are written to groups/{name}/logs/container-{timestamp}.log and the promise resolves with the final output. Error logs include only input metadata (prompt length and session ID) rather than the full prompt to avoid persisting user conversation content on disk.
Mounts are built per-group in src/container-runner.ts:
Path
Main Group
Non-Main Group
Mode
Project root
/workspace/project
Not mounted
Read-only
Group folder
/workspace/group
/workspace/group
Read-write
Global memory
Via project mount
/workspace/global (if exists)
Read-only
Claude sessions
/home/node/.claude
/home/node/.claude
Read-write
IPC namespace
/workspace/ipc
/workspace/ipc
Read-write
Agent runner src
/app/src
/app/src
Read-write
Additional mounts
Configurable
Configurable
Per-config
Each group gets its own copy of the agent-runner source in data/sessions/{group}/agent-runner-src/, allowing per-group customization without affecting other groups.
The hard timeout is calculated as Math.max(configTimeout, IDLE_TIMEOUT + 30_000), ensuring a 30-second gap between idle shutdown and the hard kill. With default settings (both 30 minutes), the hard timeout is 30 minutes 30 seconds, giving the _close sentinel time to trigger graceful shutdown before the hard kill fires.