feat: openclaw-style secrets (env.vars + \) and per-task model routing
- Replace python-dotenv with config.json env.vars block + \ substitution - Add models section for per-task model routing (heartbeat, subagent, default) - Heartbeat/subagent tasks can use different models/providers than main chat - Remove python-dotenv from dependencies - Update all docs to reflect new config approach - Reorganize docs into project/ and research/ subdirectories
This commit is contained in:
214
docs/research/nanoclaw.md
Normal file
214
docs/research/nanoclaw.md
Normal file
@@ -0,0 +1,214 @@
|
||||
# 🦀 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
|
||||
|
||||
```mermaid
|
||||
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
|
||||
|
||||
```mermaid
|
||||
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.md` memory file
|
||||
- Mounted into the group's container
|
||||
- Complete filesystem isolation between groups
|
||||
|
||||
---
|
||||
|
||||
## Security Model
|
||||
|
||||
```mermaid
|
||||
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
|
||||
|
||||
1. **Small enough to understand** — Read the entire codebase in ~8 minutes
|
||||
2. **Secure by isolation** — Linux containers, not permission checks
|
||||
3. **Built for one user** — Not a framework, working software for personal use
|
||||
4. **Customization = code changes** — No config sprawl, modify the code directly
|
||||
5. **AI-native** — Claude Code handles setup (`/setup`), debugging, customization
|
||||
6. **Skills over features** — Don't add features to codebase, add skills that transform forks
|
||||
7. **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
|
||||
|
||||
```bash
|
||||
# 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)
|
||||
Reference in New Issue
Block a user