bash nanoclaw.sh and follow the wizard — quick start covers that flow end to end.
Requirements
Two hosts the installer explicitly flags in pre-flight:
- Google Compute Engine VMs — GCE blocks the sudo commands setup needs, so NanoClaw is unlikely to run there. The installer detects GCE via DMI and warns before doing anything. Use a different provider.
- Root on Linux — discouraged. The installer offers instructions for creating a regular user instead. If you insist, it installs a system-level systemd unit rather than a user one.
What’s installed for you
nanoclaw.sh installs everything below if it’s missing. You don’t need to pre-install any of it.
Build tools (Xcode Command Line Tools on macOS,
gcc/make on Linux) are checked and reported but not installed. They only matter if better-sqlite3 has to compile from source — setup verifies the native binding loads and fails loudly if it doesn’t.
What the installer does under the hood
bash nanoclaw.sh is a three-stage chain:
nanoclaw.sh— pre-flight checks (RAM floor, GCE detection, root warning, Homebrew prompt on macOS), then runs the bootstrap under a spinner. Bash only — nothing else exists on the machine yet.setup.sh— detects the platform (macOS / Linux / WSL), installs Node 22 viasetup/install-node.shif Node 20+ isn’t present, gets pnpm onto the PATH, runspnpm install --frozen-lockfile, and verifies thebetter-sqlite3native module loads.pnpm run setup:auto— the interactive wizard (setup/auto.ts). This is where the container build, OneCLI vault, provider auth, service install, and channel pairing happen. Quick start walks through every wizard step.
logs/setup.log (one entry per step) and verbatim per-step output under logs/setup-steps/NN-name.log. When something fails, start there.
One runtime on the host, another in the container
NanoClaw deliberately splits runtimes:- Host: Node 20+ and pnpm. The wizard compiles TypeScript with
tscand the service runsnode dist/index.js. - Agent container: Bun 1.3.12 runs the agent-runner TypeScript directly — no build step. The image (from
container/Dockerfile) is based onnode:22-slimwith Chromium for browser automation and globally installed CLIs —@anthropic-ai/claude-codeandagent-browser, each pinned to an exact version for reproducibility (the Vercel CLI is opt-in via/add-vercel). The versions live incontainer/cli-tools.json(installed byinstall-cli-tools.sh).
- Agent source is never baked into the image. The host bind-mounts
container/agent-runner/srcread-only at/app/src, so agent-runner changes take effect on the next container spawn without a rebuild. The host’s ownsrc/is different: the service runs the compileddist/, so host changes needpnpm run buildand a service restart. - The image is per-checkout:
nanoclaw-agent-v2-<slug>:latest, where the slug is the first 8 hex chars ofsha1(projectRoot). Two NanoClaw installs on one host never clobber each other’s image, service, or containers.
agent-image in versions.json — implemented by container/pull.sh — and retags it to the same local tag a build would produce. The choice persists as NANOCLAW_HARDENED_IMAGE in .env. See Get started with the Echo hardened runtime.
Docker is the only supported runtime. src/container-runtime.ts hardcodes the binary (CONTAINER_RUNTIME_BIN = 'docker') behind a single-file abstraction — all runtime-specific logic lives in that one file, but nothing else is wired up today.
If you render Chinese, Japanese, or Korean text, set INSTALL_CJK_FONTS=true in .env before the container build — it adds Noto CJK fonts (~200 MB) to the image.
Manual installation
If you’d rather not runnanoclaw.sh (or it failed partway), the pieces compose by hand:
setup:auto is the same wizard the one-liner hands off to — it builds the container image, sets up credentials, and installs the background service. Without it, you can run the host in the foreground:
Re-running individual steps
pnpm run setup is a step runner, not a second wizard. Use it to re-run one piece of setup without going through the whole flow:
timezone, set-env, environment, container, register, pair-telegram, groups, whatsapp-auth, signal-auth, mounts, service, verify, onecli, auth, provider-auth, cli-agent, registry, registry-reconcile.
Scripting the wizard
setup:auto reads environment variables for unattended or partial runs:
For Anthropic-compatible custom endpoints, set
ANTHROPIC_BASE_URL in .env — the host passes it through to the agent SDK inside the container.
Running as a service
The wizard’s service step compiles TypeScript (pnpm run build), writes a service definition that runs node dist/index.js from the project root, starts it, and symlinks bin/ncl into ~/.local/bin so the ncl CLI works from anywhere. Service names embed the per-checkout slug, so look yours up rather than guessing.
- macOS (launchd)
- Linux (systemd)
- No systemd (WSL fallback)
The plist lands at
~/Library/LaunchAgents/com.nanoclaw-v2-<slug>.plist with RunAtLoad and KeepAlive — it starts at login and restarts on crash.Where files live
Everything stateful lives inside the checkout, with two exceptions: security allowlists in~/.config/nanoclaw/ (kept outside the project so they’re never mounted into containers) and the service definition.
nanoclaw
src
dist
container
groups
main
instructions.prepend.md
memory
CLAUDE.md
container.json
data
v2.db
v2-sessions
{agent_group_id}
{session_id}
.claude-shared
env
ipc
cli.sock
logs
bin
.env
nanoclaw.sh
Next steps
Quick start
The one-command flow and the wizard, step by step.
Architecture
How the host, containers, and the two-DB session model fit together.
The ncl CLI
Inspect agents, groups, and sessions from the command line.
Troubleshooting
Setup failures start at
logs/setup.log; runtime issues at logs/nanoclaw.log.