| name | debug |
| description | Debug container agent issues. Use when things aren't working, container fails, authentication problems, or to understand how the container system works. Covers logs, environment variables, mounts, and common issues. |
ClaudeClaw Container & Sandbox Debugging
This guide covers debugging the agent execution system (container and sandbox runtimes).
Architecture Overview
Host (macOS) Container (Linux VM)
─────────────────────────────────────────────────────────────
src/orchestrator/container-runner.ts agent/runner/
│ │
│ spawns container │ runs Claude Agent SDK
│ with volume mounts │ with MCP servers
│ │
├── data/env/env ──────────────> /workspace/env-dir/env
├── groups/{folder} ───────────> /workspace/group
├── data/ipc/{folder} ────────> /workspace/ipc
├── data/sessions/{folder}/.claude/ ──> /home/node/.claude/ (isolated per-group)
└── (main only) project root ──> /workspace/project
Important: The container runs as user node with HOME=/home/node. Session files must be mounted to /home/node/.claude/ (not /root/.claude/) for session resumption to work.
Log Locations
| Log | Location | Content |
|---|
| Main app logs | logs/claudeclaw.log | Host-side WhatsApp, routing, container spawning |
| Main app errors | logs/claudeclaw.error.log | Host-side errors |
| Container run logs | groups/{folder}/logs/container-*.log | Per-run: input, mounts, stderr, stdout |
| Claude sessions | ~/.claude/projects/ | Claude Code session history |
Enabling Debug Logging
Set LOG_LEVEL=debug for verbose output:
LOG_LEVEL=debug npm run dev
<key>LOG_LEVEL</key>
<string>debug</string>
Debug level shows:
- Full mount configurations
- Container command arguments
- Real-time container stderr
Common Issues
1. "Claude Code process exited with code 1"
Check the container log file in groups/{folder}/logs/container-*.log
Common causes:
Missing Authentication
Invalid API key · Please run /login
Fix: Ensure .env file exists with either OAuth token or API key:
cat .env
Root User Restriction
--dangerously-skip-permissions cannot be used with root/sudo privileges
Fix: Container must run as non-root user. Check Dockerfile has USER node.
2. Environment Variables Not Passing
Runtime note: Environment variables passed via -e may be lost when using -i (interactive/piped stdin).
Workaround: The system extracts only authentication variables (CLAUDE_CODE_OAUTH_TOKEN, ANTHROPIC_API_KEY) from .env and mounts them for sourcing inside the container. Other env vars are not exposed.
To verify env vars are reaching the container:
echo '{}' | docker run -i \
-v $(pwd)/data/env:/workspace/env-dir:ro \
--entrypoint /bin/bash claudeclaw-agent:latest \
-c 'export $(cat /workspace/env-dir/env | xargs); echo "OAuth: ${#CLAUDE_CODE_OAUTH_TOKEN} chars, API: ${#ANTHROPIC_API_KEY} chars"'
3. Mount Issues
Container mount notes:
To check what's mounted inside a container:
docker run --rm --entrypoint /bin/bash claudeclaw-agent:latest -c 'ls -la /workspace/'
Expected structure:
/workspace/
├── env-dir/env # Environment file (CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY)
├── group/ # Current group folder (cwd)
├── project/ # Project root (main channel only)
├── global/ # Global CLAUDE.md (non-main only)
├── ipc/ # Inter-process communication
│ ├── messages/ # Outgoing WhatsApp messages
│ ├── tasks/ # Scheduled task commands
│ ├── current_tasks.json # Read-only: scheduled tasks visible to this group
│ └── available_groups.json # Read-only: WhatsApp groups for activation (main only)
└── extra/ # Additional custom mounts
4. Permission Issues
The container runs as user node (uid 1000). Check ownership:
docker run --rm --entrypoint /bin/bash claudeclaw-agent:latest -c '
whoami
ls -la /workspace/
ls -la /app/
'
All of /workspace/ and /app/ should be owned by node.
5. Session Not Resuming / "Claude Code process exited with code 1"
If sessions aren't being resumed (new session ID every time), or Claude Code exits with code 1 when resuming:
Root cause: The SDK looks for sessions at $HOME/.claude/projects/. Inside the container, HOME=/home/node, so it looks at /home/node/.claude/projects/.
Check the mount path:
grep -A3 "Claude sessions" src/orchestrator/container-runner.ts
Verify sessions are accessible:
docker run --rm --entrypoint /bin/bash \
-v ~/.claude:/home/node/.claude \
claudeclaw-agent:latest -c '
echo "HOME=$HOME"
ls -la $HOME/.claude/projects/ 2>&1 | head -5
'
Fix: Ensure container-runner.ts mounts to /home/node/.claude/:
mounts.push({
hostPath: claudeDir,
containerPath: '/home/node/.claude',
readonly: false
});
6. MCP Server Failures
If an MCP server fails to start, the agent may exit. Check the container logs for MCP initialization errors.
Manual Container Testing
Test the full agent flow:
mkdir -p data/env groups/test
cp .env data/env/env
echo '{"prompt":"What is 2+2?","groupFolder":"test","chatJid":"test@g.us","isMain":false}' | \
docker run -i \
-v $(pwd)/data/env:/workspace/env-dir:ro \
-v $(pwd)/groups/test:/workspace/group \
-v $(pwd)/data/ipc:/workspace/ipc \
claudeclaw-agent:latest
Test Claude Code directly:
docker run --rm --entrypoint /bin/bash \
-v $(pwd)/data/env:/workspace/env-dir:ro \
claudeclaw-agent:latest -c '
export $(cat /workspace/env-dir/env | xargs)
claude -p "Say hello" --dangerously-skip-permissions --allowedTools ""
'
Interactive shell in container:
docker run --rm -it --entrypoint /bin/bash claudeclaw-agent:latest
SDK Options Reference
The agent-runner uses these Claude Agent SDK options:
query({
prompt: input.prompt,
options: {
cwd: '/workspace/group',
allowedTools: ['Bash', 'Read', 'Write', ...],
permissionMode: 'bypassPermissions',
allowDangerouslySkipPermissions: true,
settingSources: ['project'],
mcpServers: { ... }
}
})
Important: allowDangerouslySkipPermissions: true is required when using permissionMode: 'bypassPermissions'. Without it, Claude Code exits with code 1.
Rebuilding After Changes
npm run build
./src/runtimes/docker/build.sh
docker builder prune -af
./src/runtimes/docker/build.sh
Checking Container Image
docker images
docker run --rm --entrypoint /bin/bash claudeclaw-agent:latest -c '
echo "=== Node version ==="
node --version
echo "=== Claude Code version ==="
claude --version
echo "=== Installed packages ==="
ls /app/node_modules/
'
Session Persistence
Claude sessions are stored per-group in data/sessions/{group}/.claude/ for security isolation. Each group has its own session directory, preventing cross-group access to conversation history.
Critical: The mount path must match the container user's HOME directory:
- Container user:
node
- Container HOME:
/home/node
- Mount target:
/home/node/.claude/ (NOT /root/.claude/)
To clear sessions:
rm -rf data/sessions/
rm -rf data/sessions/{groupFolder}/.claude/
sqlite3 store/messages.db "DELETE FROM sessions WHERE group_folder = '{groupFolder}'"
To verify session resumption is working, check the logs for the same session ID across messages:
grep "Session initialized" logs/claudeclaw.log | tail -5
IPC Debugging
The container communicates back to the host via files in /workspace/ipc/:
ls -la data/ipc/messages/
ls -la data/ipc/tasks/
cat data/ipc/messages/*.json
cat data/ipc/main/available_groups.json
cat data/ipc/{groupFolder}/current_tasks.json
IPC file types:
messages/*.json - Agent writes: outgoing WhatsApp messages
tasks/*.json - Agent writes: task operations (schedule, pause, resume, cancel, refresh_groups)
current_tasks.json - Host writes: read-only snapshot of scheduled tasks
available_groups.json - Host writes: read-only list of WhatsApp groups (main only)
Sandbox Runtime Debugging
If RUNTIME=sandbox is set, agents run via @anthropic-ai/sandbox-runtime instead of containers.
Sandbox Architecture
Host (macOS/Linux)
───────────────────────────────────────────
src/orchestrator/sandbox-runner.ts
│
│ spawns sandboxed process via srt CLI
│ with kernel-enforced filesystem/network
│
├── CLAUDECLAW_GROUP_DIR → groups/{folder}
├── CLAUDECLAW_IPC_DIR → data/ipc/{folder}
├── CLAUDECLAW_PROJECT_DIR → project root (read-only)
├── CLAUDECLAW_GLOBAL_DIR → groups/global (read-only)
└── CLAUDECLAW_EXTRA_DIR → additional mounts
Sandbox-Specific Issues
EPERM on all operations: The srt settings JSON file requires ALL fields including empty arrays (allowRead: []). Omit any field and the entire settings file silently fails validation — zero error messages.
Agent runner won't start (tsx/EPERM): Sandbox blocks Unix sockets needed by tsx. Fix: pre-compile with cd agent/runner && npx tsc, run with plain node.
Agent can't find paths: Check that CLAUDECLAW_*_DIR env vars are set in sandbox-runner.ts. The agent runner falls back to /workspace/* if env vars are missing.
Stale sessions after runtime switch: Switching a group between container and sandbox leaves stale session IDs. Fix: sqlite3 store/messages.db "DELETE FROM sessions"
Network blocked: Verify allowedDomains in the generated settings file includes api.anthropic.com. Check data/sandbox-settings/ for the last generated settings file.
Credential issues: Sandbox passes real credentials via env vars (not through the credential proxy). Ensure ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN is in .env.
Quick Diagnostic Script
Run this to check common issues:
echo "=== Checking ClaudeClaw Agent Setup ==="
echo -e "\n1. Authentication configured?"
[ -f .env ] && (grep -q "CLAUDE_CODE_OAUTH_TOKEN=sk-" .env || grep -q "ANTHROPIC_API_KEY=sk-" .env) && echo "OK" || echo "MISSING - add CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY to .env"
echo -e "\n2. Env file copied for container?"
[ -f data/env/env ] && echo "OK" || echo "MISSING - will be created on first run"
echo -e "\n3. Container runtime running?"
docker info &>/dev/null && echo "OK" || echo "NOT RUNNING - start Docker Desktop (macOS) or sudo systemctl start docker (Linux)"
echo -e "\n4. Container image exists?"
echo '{}' | docker run -i --entrypoint /bin/echo claudeclaw-agent:latest "OK" 2>/dev/null || echo "MISSING - run ./src/runtimes/docker/build.sh"
echo -e "\n5. Session mount path correct?"
grep -q "/home/node/.claude" src/orchestrator/container-runner.ts 2>/dev/null && echo "OK" || echo "WRONG - should mount to /home/node/.claude/, not /root/.claude/"
echo -e "\n6. Groups directory?"
ls -la groups/ 2>/dev/null || echo "MISSING - run setup"
echo -e "\n7. Recent container logs?"
ls -t groups/*/logs/container-*.log 2>/dev/null | head -3 || echo "No container logs yet"
echo -e "\n8. Session continuity working?"
SESSIONS=$(grep "Session initialized" logs/claudeclaw.log 2>/dev/null | tail -5 | awk '{print $NF}' | sort -u | wc -l)
[ "$SESSIONS" -le 2 ] && echo "OK (recent sessions reusing IDs)" || echo "CHECK - multiple different session IDs, may indicate resumption issues"