refactor: extract runtime-specific code into src/container-runtime.ts (#321)
Move all container-runtime-specific logic (binary name, mount args, stop command, startup check, orphan cleanup) into a single file so swapping runtimes only requires replacing this one file. Neutralize "Apple Container" references in comments and docs that would become incorrect after a runtime swap. References that list both runtimes as options are left unchanged. No behavior change — Apple Container remains the default runtime. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
18
docs/SPEC.md
18
docs/SPEC.md
@@ -45,7 +45,7 @@ A personal Claude assistant accessible via WhatsApp, with persistent memory per
|
||||
│ │ spawns container │
|
||||
│ ▼ │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ APPLE CONTAINER (Linux VM) │
|
||||
│ CONTAINER (Linux VM) │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ ┌──────────────────────────────────────────────────────────────┐ │
|
||||
│ │ AGENT RUNNER │ │
|
||||
@@ -75,7 +75,7 @@ A personal Claude assistant accessible via WhatsApp, with persistent memory per
|
||||
|-----------|------------|---------|
|
||||
| WhatsApp Connection | Node.js (@whiskeysockets/baileys) | Connect to WhatsApp, send/receive messages |
|
||||
| Message Storage | SQLite (better-sqlite3) | Store messages for polling |
|
||||
| Container Runtime | Apple Container | Isolated Linux VMs for agent execution |
|
||||
| Container Runtime | Containers (Linux VMs) | Isolated environments for agent execution |
|
||||
| Agent | @anthropic-ai/claude-agent-sdk (0.2.29) | Run Claude with tools and MCP servers |
|
||||
| Browser Automation | agent-browser + Chromium | Web interaction and screenshots |
|
||||
| Runtime | Node.js 20+ | Host process for routing and scheduling |
|
||||
@@ -111,7 +111,7 @@ nanoclaw/
|
||||
│ ├── mount-security.ts # Mount allowlist validation for containers
|
||||
│ ├── whatsapp-auth.ts # Standalone WhatsApp authentication
|
||||
│ ├── task-scheduler.ts # Runs scheduled tasks when due
|
||||
│ └── container-runner.ts # Spawns agents in Apple Containers
|
||||
│ └── container-runner.ts # Spawns agents in containers
|
||||
│
|
||||
├── container/
|
||||
│ ├── Dockerfile # Container image (runs as 'node' user, includes Claude Code CLI)
|
||||
@@ -196,7 +196,7 @@ export const MAX_CONCURRENT_CONTAINERS = Math.max(1, parseInt(process.env.MAX_CO
|
||||
export const TRIGGER_PATTERN = new RegExp(`^@${ASSISTANT_NAME}\\b`, 'i');
|
||||
```
|
||||
|
||||
**Note:** Paths must be absolute for Apple Container volume mounts to work correctly.
|
||||
**Note:** Paths must be absolute for container volume mounts to work correctly.
|
||||
|
||||
### Container Configuration
|
||||
|
||||
@@ -223,7 +223,7 @@ registerGroup("1234567890@g.us", {
|
||||
|
||||
Additional mounts appear at `/workspace/extra/{containerPath}` inside the container.
|
||||
|
||||
**Apple Container mount syntax note:** Read-write mounts use `-v host:container`, but readonly mounts require `--mount "type=bind,source=...,target=...,readonly"` (the `:ro` suffix doesn't work).
|
||||
**Mount syntax note:** Read-write mounts use `-v host:container`, but readonly mounts require `--mount "type=bind,source=...,target=...,readonly"` (the `:ro` suffix may not work on all runtimes).
|
||||
|
||||
### Claude Authentication
|
||||
|
||||
@@ -240,7 +240,7 @@ The token can be extracted from `~/.claude/.credentials.json` if you're logged i
|
||||
ANTHROPIC_API_KEY=sk-ant-api03-...
|
||||
```
|
||||
|
||||
Only the authentication variables (`CLAUDE_CODE_OAUTH_TOKEN` and `ANTHROPIC_API_KEY`) are extracted from `.env` and written to `data/env/env`, then mounted into the container at `/workspace/env-dir/env` and sourced by the entrypoint script. This ensures other environment variables in `.env` are not exposed to the agent. This workaround is needed because Apple Container loses `-e` environment variables when using `-i` (interactive mode with piped stdin).
|
||||
Only the authentication variables (`CLAUDE_CODE_OAUTH_TOKEN` and `ANTHROPIC_API_KEY`) are extracted from `.env` and written to `data/env/env`, then mounted into the container at `/workspace/env-dir/env` and sourced by the entrypoint script. This ensures other environment variables in `.env` are not exposed to the agent. This workaround is needed because some container runtimes lose `-e` environment variables when using `-i` (interactive mode with piped stdin).
|
||||
|
||||
### Changing the Assistant Name
|
||||
|
||||
@@ -484,7 +484,7 @@ NanoClaw runs as a single macOS launchd service.
|
||||
### Startup Sequence
|
||||
|
||||
When NanoClaw starts, it:
|
||||
1. **Ensures Apple Container system is running** - Automatically starts it if needed; kills orphaned NanoClaw containers from previous runs
|
||||
1. **Ensures container runtime is running** - Automatically starts it if needed; kills orphaned NanoClaw containers from previous runs
|
||||
2. Initializes the SQLite database (migrates from JSON files if they exist)
|
||||
3. Loads state from SQLite (registered groups, sessions, router state)
|
||||
4. Connects to WhatsApp (on `connection.open`):
|
||||
@@ -557,7 +557,7 @@ tail -f logs/nanoclaw.log
|
||||
|
||||
### Container Isolation
|
||||
|
||||
All agents run inside Apple Container (lightweight Linux VMs), providing:
|
||||
All agents run inside containers (lightweight Linux VMs), providing:
|
||||
- **Filesystem isolation**: Agents can only access mounted directories
|
||||
- **Safe Bash access**: Commands run inside the container, not on your Mac
|
||||
- **Network isolation**: Can be configured per-container if needed
|
||||
@@ -605,7 +605,7 @@ chmod 700 groups/
|
||||
| Issue | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| No response to messages | Service not running | Check `launchctl list | grep nanoclaw` |
|
||||
| "Claude Code process exited with code 1" | Apple Container failed to start | Check logs; NanoClaw auto-starts container system but may fail |
|
||||
| "Claude Code process exited with code 1" | Container runtime failed to start | Check logs; NanoClaw auto-starts container runtime but may fail |
|
||||
| "Claude Code process exited with code 1" | Session mount path wrong | Ensure mount is to `/home/node/.claude/` not `/root/.claude/` |
|
||||
| Session not continuing | Session ID not saved | Check SQLite: `sqlite3 store/messages.db "SELECT * FROM sessions"` |
|
||||
| Session not continuing | Mount path mismatch | Container user is `node` with HOME=/home/node; sessions must be at `/home/node/.claude/` |
|
||||
|
||||
Reference in New Issue
Block a user