6.2 KiB
6.2 KiB
🦀 NanoClaw — Architecture & How It Works
Minimal, Security-First Personal AI Assistant — built on Claude Agent SDK with container isolation.
Overview
NanoClaw is a minimalist personal AI assistant that prioritizes security through container isolation and understandability through small codebase size. It runs on Claude Agent SDK (Claude Code) and uses WhatsApp as its primary channel. Each group chat runs in its own isolated Linux container.
| Attribute | Value |
|---|---|
| Language | TypeScript (Node.js 20+) |
| Codebase Size | ~34.9k tokens (~17% of Claude context window) |
| Config | No config files — code changes only |
| AI Runtime | Claude Agent SDK (Claude Code) |
| Primary Channel | WhatsApp (Baileys) |
| Isolation | Apple Container (macOS) / Docker (Linux) |
Architecture Flowchart
graph TB
subgraph WhatsApp["📱 WhatsApp"]
WA["WhatsApp Client\n(Baileys)"]
end
subgraph Core["🧠 Core Process (Single Node.js)"]
IDX["Orchestrator\n(index.ts)"]
DB["SQLite DB\n(db.ts)"]
GQ["Group Queue\n(group-queue.ts)"]
TS["Task Scheduler\n(task-scheduler.ts)"]
IPC["IPC Watcher\n(ipc.ts)"]
RT["Router\n(router.ts)"]
end
subgraph Containers["🐳 Isolated Containers"]
C1["Container 1\nGroup A\n(CLAUDE.md)"]
C2["Container 2\nGroup B\n(CLAUDE.md)"]
C3["Container 3\nMain Channel\n(CLAUDE.md)"]
end
subgraph Memory["💾 Per-Group Memory"]
M1["groups/A/CLAUDE.md"]
M2["groups/B/CLAUDE.md"]
M3["groups/main/CLAUDE.md"]
end
WA --> IDX
IDX --> DB
IDX --> GQ
GQ --> Containers
TS --> Containers
Containers --> IPC
IPC --> RT
RT --> WA
C1 --- M1
C2 --- M2
C3 --- M3
Message Flow
sequenceDiagram
participant User
participant WA as WhatsApp (Baileys)
participant IDX as Orchestrator
participant DB as SQLite
participant GQ as Group Queue
participant Container as Container (Claude SDK)
participant IPC as IPC Watcher
User->>WA: Send message with @Andy
WA->>IDX: New message event
IDX->>DB: Store message
IDX->>GQ: Enqueue (per-group, concurrency limited)
GQ->>Container: Spawn Claude agent container
Note over Container: Mounts only group's filesystem
Note over Container: Reads group-specific CLAUDE.md
Container->>Container: Claude processes with tools
Container->>IPC: Write response to filesystem
IPC->>IDX: Detect new response file
IDX->>WA: Send reply
WA->>User: Display response
Key Components
1. Orchestrator (src/index.ts)
The single entry point that manages:
- WhatsApp connection state
- Message polling loop
- Agent invocation decisions
- State management for groups and sessions
2. WhatsApp Channel (src/channels/whatsapp.ts)
- Uses Baileys library for WhatsApp Web connection
- Handles authentication via QR code scan
- Manages send/receive of messages
- Supports media messages
3. Container Runner (src/container-runner.ts)
The security core of NanoClaw:
- Spawns streaming Claude Agent SDK containers
- Each group runs in its own Linux container
- Apple Container on macOS, Docker on Linux
- Only explicitly mounted directories are accessible
- Bash commands run INSIDE the container, not on host
4. SQLite Database (src/db.ts)
- Stores messages, groups, sessions, and state
- Per-group message history
- Session continuity tracking
5. Group Queue (src/group-queue.ts)
- Per-group message queue
- Global concurrency limit
- Ensures one agent invocation per group at a time
6. IPC System (src/ipc.ts)
- Filesystem-based inter-process communication
- Container writes response to mounted directory
- IPC watcher detects and processes response files
- Handles task results from scheduled jobs
7. Task Scheduler (src/task-scheduler.ts)
- Recurring jobs that run Claude in containers
- Jobs can message the user back
- Managed from the main channel (self-chat)
8. Router (src/router.ts)
- Formats outbound messages
- Routes responses to correct WhatsApp recipient
9. Per-Group Memory (groups/*/CLAUDE.md)
- Each group has its own
CLAUDE.mdmemory file - Mounted into the group's container
- Complete filesystem isolation between groups
Security Model
graph LR
subgraph Host["🖥️ Host System"]
NanoClaw["NanoClaw Process"]
end
subgraph Container1["🐳 Container (Group A)"]
Agent1["Claude Agent"]
FS1["Mounted: groups/A/"]
end
subgraph Container2["🐳 Container (Group B)"]
Agent2["Claude Agent"]
FS2["Mounted: groups/B/"]
end
NanoClaw -->|"Spawns"| Container1
NanoClaw -->|"Spawns"| Container2
style Container1 fill:#e8f5e9
style Container2 fill:#e8f5e9
- OS-level isolation vs. application-level permission checks
- Agents can only see what's explicitly mounted
- Bash commands run in container, not on host
- No shared memory between groups
Philosophy & Design Decisions
- Small enough to understand — Read the entire codebase in ~8 minutes
- Secure by isolation — Linux containers, not permission checks
- Built for one user — Not a framework, working software for personal use
- Customization = code changes — No config sprawl, modify the code directly
- AI-native — Claude Code handles setup (
/setup), debugging, customization - Skills over features — Don't add features to codebase, add skills that transform forks
- Best harness, best model — Claude Agent SDK gives Claude Code superpowers
Agent Swarms (Unique Feature)
NanoClaw is the first personal AI assistant to support Agent Swarms:
- Spin up teams of specialized agents
- Agents collaborate within your chat
- Each agent runs in its own container
Usage
# Setup (Claude Code handles everything)
git clone https://github.com/gavrielc/nanoclaw.git
cd nanoclaw
claude
# Then run /setup
# Talk to your assistant
@Andy send me a daily summary every morning at 9am
@Andy review the git history and update the README
Trigger word: @Andy (customizable via code changes)