Your personal AI assistant - like Hermes or OpenClaw, but distilled to its essentials.
~2,000 lines of TypeScript. No dashboard. No bloat. Just the loop.
User: "summarize the errors in app.log from the last 10 minutes"
Bot: [reads file] [runs grep] β "Found 3 ERROR lines: connection timeout (Γ2), OOM at 14:32"
Most agent runtimes ship hundreds of abstractions, dozens of providers, and dashboards you never open. NanoClaw is a design: the fewest moving parts that still make a capable, recoverable personal assistant.
| NanoClaw | OpenClaw | Hermes Agent | |
|---|---|---|---|
| Lines of code | ~2,000 | ~500,000β800,000 | ~10,000β15,000 |
| Runtime | Bun + TypeScript | TS Β· Swift Β· Kotlin Β· more | Python |
| Chat platforms | 3 (TG Β· Slack Β· Discord) | 20+ (WhatsApp Β· Signal Β· iMessage Β· WeChat Β· IRC Β· β¦) | 6 (TG Β· Discord Β· Slack Β· WhatsApp Β· Signal Β· CLI) |
| Install | bun install |
npm install -g openclaw + onboard wizard |
curl β¦ | bash installer |
| Config | Single .env file |
JSON5 config + openclaw onboard wizard |
hermes setup wizard + hermes config set |
| Per-peer concurrency | β single-slot pending buffer (newest wins) | β | β |
| Voice | β | β wake word + talk mode (macOS Β· iOS Β· Android) | β (memo transcription only) |
| Subagents | β | β multi-agent routing | β spawn isolated subagents |
| Self-improvement | β | β | β (DSPy + GEPA) |
| Skills marketplace | β | β ClawHub | β agentskills.io |
| Companion apps | β | β macOS menu bar Β· iOS Β· Android | β |
| Deployment | Local process | Daemon (launchd/systemd) Β· Docker | Local Β· Docker Β· SSH Β· Modal (serverless) |
| Hack-friendly | β read in an afternoon | Needs weeks to orient | Moderate (~10k LOC) |
|
β’ Streaming tool-call loop |
β’ File read / write / edit |
β’ Anthropic + OpenAI |
β’ Prompt / auto / read-only modes |
β’ Isolated OS process per run |
You need two tokens: one for the LLM, one for the chat platform.
LLM (pick one)
| Provider | Where to get it | Env var |
|---|---|---|
| OpenRouter (recommended) | openrouter.ai/keys - free tier available, access to all models | OPENROUTER_API_KEY |
| Anthropic | console.anthropic.com/keys | ANTHROPIC_API_KEY |
| OpenAI | platform.openai.com/api-keys | OPENAI_API_KEY |
Chat platform (pick one)
| Platform | Steps |
|---|---|
| Discord | discord.com/developers/applications - New Application - Bot - Reset Token. Enable Message Content Intent. Invite bot with bot + applications.commands scopes. |
| Telegram | Message @BotFather on Telegram - /newbot - copy the token. |
| Slack | api.slack.com/apps - Create App - Socket Mode on - add chat:write + im:history scopes - install to workspace. You need both SLACK_BOT_TOKEN (xoxb-) and SLACK_APP_TOKEN (xapp-). |
git clone https://github.com/Engineering4AI/nanoclaw
cd nanoclaw
bun install # core deps
bun install grammy # + Telegram adapter
# bun install @slack/bolt # + Slack adapter
# bun install discord.js # + Discord adapter
cp .env.example .env
# edit .env β set your API key + bot token
bun src/main.tsThat's it. First run bootstraps ~/.nanoclaw/config.yaml and workspace files automatically.
Everything lives in .env β no code changes needed:
# LLM (default: OpenRouter)
OPENROUTER_API_KEY=sk-or-...
NANOCLAW_MODEL=anthropic/claude-sonnet-4-6
NANOCLAW_PROVIDER=openai_compatible
NANOCLAW_BASE_URL=https://openrouter.ai/api/v1
# Platform (pick one)
DISCORD_TOKEN=your-discord-bot-token
# TELEGRAM_TOKEN=your-telegram-bot-token
# SLACK_BOT_TOKEN=xoxb-...
# SLACK_APP_TOKEN=xapp-...
# Agent behavior
NANOCLAW_PERMISSION_MODE=default # default | auto | plan
# Cron jobs (optional) β semicolon-separated: SCHEDULE|PROMPT[|label]
# NANOCLAW_CRON=30m|check disk usage and warn if above 90%|disk;1h|summarize today's errors in ~/app.log|logsSwitch to Anthropic directly:
ANTHROPIC_API_KEY=sk-ant-...
NANOCLAW_PROVIDER=anthropic
NANOCLAW_MODEL=claude-opus-4-8flowchart TD
TG[Telegram] & SL[Slack] & DC[Discord] --> R
subgraph Gateway
R["Router\n(1 lock / peer)"]
SS[(SessionStore\nbun:sqlite)]
R <--> SS
end
R --> AL
subgraph AgentLoop["Agent Loop"]
AL["stream LLM response"] --> TD{tool_use?}
TD -->|yes| PD["parallel dispatch\n(Promise.all)"]
TD -->|no| OUT[return text]
PD --> AL
AL --> CP["compact @ 80% context"]
AL --> JP[(JSONL\npersistence)]
end
PD --> TR
subgraph ToolRegistry["Tool Registry"]
TR["permission_check"] --> PH[pre_hook]
PH --> EX["execute\n(read Β· write Β· edit Β· bash Β· fetch Β· search)"]
EX --> POH[post_hook]
POH --> RS["result β€ 50 KB"]
end
RS --> PD
src/
main.ts # entry point β reads env, starts gateway
config.ts # Config interface + YAML load
permissions.ts # PermissionPolicy, 3 modes, sensitive-path guard
hooks.ts # pre/post hook registry
providers/
base.ts # Provider ABC, StreamResponse, ToolUse, ToolResult
anthropic.ts # AnthropicProvider β backoff on 429/529
openai.ts # OpenAIProvider β converts tool schema to OpenAI format
index.ts # getProvider() factory
tools/
index.ts # Tool type, executeParallel(), buildRegistry()
files.ts # read_file, write_file, edit_file
shell.ts # run_bash (120s timeout)
web.ts # web_fetch (HTML stripped), web_search (DuckDuckGo)
agent/
loop.ts # run() β the agent loop
compactor.ts # compact when estimated tokens > 80% context window
session.ts # JSONL append-only persistence per session_id
memory/
workspace.ts # bootstrap AGENTS.md/USER.md, build system prompt
gateway/
index.ts # GatewayConfig, start()
session.ts # SessionStore β bun:sqlite-backed
router.ts # onMessage β lock β agent loop β chunk β deliver
adapters/
base.ts # ChannelAdapter abstract class
telegram.ts # grammy polling
slack.ts # @slack/bolt socket mode
discord.ts # discord.js intents
ui/
App.tsx # React Ink root β gateway log + active sessions view
SessionPanel.tsx # Per-session message stream
StatusBar.tsx # Model Β· permission mode Β· uptime
NanoClaw ships with two workspace files that persist across sessions:
~/.nanoclaw/workspace/AGENTS.mdβ operating instructions, task notes, agent persona. Injected as system prompt prefix.~/.nanoclaw/workspace/USER.mdβ user profile, preferences. Injected after AGENTS.md.
Edit these files to shape how the agent behaves. No vector store, no database β just files.
| Feature | Add it when... |
|---|---|
| Multi-agent board | You have >1 agent profile needing coordination |
| MCP servers | You hit a tool gap the 6 kernel tools can't cover |
| Dashboard / TUI | Gateway is the interface; the Ink UI is optional |
| Skills / macros | AGENTS.md handles this at minimal scale |
| Trajectory recording | You need RL training data |
Each agent run is an OS process. Coordination state lives outside the process.
Session JSONL survives crashes. SQLite session store survives gateway restarts. A restart picks up where it left off. This constraint keeps everything else simple.
