> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nanoclaw.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Installation

> Requirements, what the installer does under the hood, manual setup, service management, and where NanoClaw puts its files.

This page is the depth companion to [Quick start](/quickstart): what the installer actually does, how to install by hand, how the background service works, and where everything lands on disk. If you just want a running assistant, run `bash nanoclaw.sh` and follow the wizard — quick start covers that flow end to end.

## Requirements

|                  | Requirement                                                                                                                                                                                                                                                                                                                |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Platform         | macOS or Linux. Windows works through WSL2 — the installer detects WSL and treats it as Linux.                                                                                                                                                                                                                             |
| RAM              | 4 GB+. The installer warns below 3,700 MB (a "4 GB" VM typically reports 3,700–3,900 MB after kernel reserves) and lets you override.                                                                                                                                                                                      |
| Node.js          | 20 or newer on the host (`engines` in `package.json`). Installed for you if missing.                                                                                                                                                                                                                                       |
| git              | To clone the repository. Not auto-installed.                                                                                                                                                                                                                                                                               |
| Agent credential | A credential for the provider you pick at setup. Default **Claude**: a subscription (browser sign-in), an OAuth token (`sk-ant-oat…`), or an Anthropic API key (`sk-ant-api…`). Pick **Codex** instead and it's a ChatGPT subscription or an OpenAI API key. Either way it lands in the OneCLI vault, never the container. |

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.

| Dependency            | Where it runs | How it's installed                                                                                                                                                                                                                                                  |
| --------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Homebrew (macOS only) | Host          | Official installer, after a prompt. Pulls in Apple's Command Line Tools (can take 5–10 minutes on a factory Mac).                                                                                                                                                   |
| Node 22               | Host          | `uvx nodeenv -n lts` if `uvx` is present; otherwise `brew install node@22` (macOS) or NodeSource + `apt-get` (Linux). Skipped if you already have Node 20+.                                                                                                         |
| pnpm 10               | Host          | `corepack enable`, falling back to `npm install -g pnpm@<pinned>` at the version from `packageManager`.                                                                                                                                                             |
| Docker                | Host          | `brew install --cask docker` (macOS) or `get.docker.com` + `usermod -aG docker` (Linux/WSL). Setup also starts the daemon and works around stale group membership (`sg docker` re-exec, or a temporary ACL on the socket) so you don't have to log out and back in. |
| OneCLI vault          | Host          | Installed by the wizard, or reuses an existing healthy OneCLI instance if it finds one.                                                                                                                                                                             |
| Bun 1.3.12            | Container     | Baked into the agent container image. Never touches the host.                                                                                                                                                                                                       |

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:

1. **`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.
2. **`setup.sh`** — detects the platform (macOS / Linux / WSL), installs Node 22 via `setup/install-node.sh` if Node 20+ isn't present, gets pnpm onto the PATH, runs `pnpm install --frozen-lockfile`, and verifies the `better-sqlite3` native module loads.
3. **`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](/quickstart) walks through every wizard step.

```mermaid theme={null}
flowchart LR
    N["nanoclaw.sh<br/>pre-flight"] --> S["setup.sh<br/>bootstrap"] --> A["setup:auto<br/>wizard"]
```

Every run writes two logs: a progression log at `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 `tsc` and the service runs `node 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 on `node:22-slim` with Chromium for browser automation and globally installed CLIs — `@anthropic-ai/claude-code` and `agent-browser`, each pinned to an exact version for reproducibility (the Vercel CLI is opt-in via `/add-vercel`). The versions live in `container/cli-tools.json` (installed by `install-cli-tools.sh`).

Two consequences worth knowing:

* **Agent source is never baked into the image.** The host bind-mounts `container/agent-runner/src` read-only at `/app/src`, so agent-runner changes take effect on the next container spawn without a rebuild. The host's own `src/` is different: the service runs the compiled `dist/`, so host changes need `pnpm run build` and a service restart.
* **The image is per-checkout**: `nanoclaw-agent-v2-<slug>:latest`, where the slug is the first 8 hex chars of `sha1(projectRoot)`. Two NanoClaw installs on one host never clobber each other's image, service, or containers.

The container step can fetch a pre-built image instead of building one: sign in with your NanoClaw account, and setup pulls the reference pinned as `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](/guides/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 run `nanoclaw.sh` (or it failed partway), the pieces compose by hand:

```bash theme={null}
git clone https://github.com/nanocoai/nanoclaw.git
cd nanoclaw
pnpm install
pnpm run setup:auto
```

`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:

```bash theme={null}
pnpm run build && pnpm start   # compiled, what the service runs
pnpm run dev                   # tsx, no build step
```

### 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:

```bash theme={null}
pnpm run setup -- --step container   # rebuild and re-test the agent image
pnpm run setup -- --step service     # rebuild TypeScript and reinstall the service
pnpm run setup -- --step verify      # end-to-end health check
```

Available steps: `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:

| Env var                 | Use                                                                                                                                                                 |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NANOCLAW_SKIP`         | Comma-separated wizard steps to skip: `environment`, `container`, `onecli`, `auth`, `mounts`, `service`, `cli-agent`, `first-chat`, `timezone`, `channel`, `verify` |
| `NANOCLAW_DISPLAY_NAME` | Skip the "what should the assistant call you" prompt                                                                                                                |
| `NANOCLAW_AGENT_NAME`   | Set the messaging-channel agent name                                                                                                                                |
| `SECRET_NAME`           | OneCLI secret name (default: `Anthropic`)                                                                                                                           |
| `HOST_PATTERN`          | OneCLI host pattern (default: `api.anthropic.com`)                                                                                                                  |

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](/operate/ncl-cli) works from anywhere. Service names embed the per-checkout slug, so look yours up rather than guessing.

<Tabs>
  <Tab title="macOS (launchd)">
    The plist lands at `~/Library/LaunchAgents/com.nanoclaw-v2-<slug>.plist` with `RunAtLoad` and `KeepAlive` — it starts at login and restarts on crash.

    ```bash theme={null}
    # Find your label
    launchctl list | grep nanoclaw

    # Restart
    launchctl kickstart -k gui/$(id -u)/com.nanoclaw-v2-<slug>

    # Stop / start
    launchctl unload ~/Library/LaunchAgents/com.nanoclaw-v2-<slug>.plist
    launchctl load   ~/Library/LaunchAgents/com.nanoclaw-v2-<slug>.plist

    # Logs (stdout and stderr go to files, not the system log)
    tail -f logs/nanoclaw.log logs/nanoclaw.error.log
    ```
  </Tab>

  <Tab title="Linux (systemd)">
    A user unit lands at `~/.config/systemd/user/nanoclaw-v2-<slug>.service` with `Restart=always`. (If you set up as root, it's a system unit at `/etc/systemd/system/` instead — drop the `--user` flag.)

    ```bash theme={null}
    # Find your unit
    systemctl --user list-units 'nanoclaw-v2-*'

    systemctl --user restart nanoclaw-v2-<slug>
    systemctl --user status  nanoclaw-v2-<slug>

    # Logs append to files, not the journal
    tail -f logs/nanoclaw.log logs/nanoclaw.error.log
    ```

    <Note>
      Setup runs `loginctl enable-linger` so the user service survives SSH logout. Verify with `loginctl show-user $USER | grep Linger`.
    </Note>
  </Tab>

  <Tab title="No systemd (WSL fallback)">
    On WSL (or any Linux) without a systemd user session, setup writes a wrapper script instead of a unit:

    ```bash theme={null}
    bash start-nanoclaw.sh        # start (stops any previous instance first)
    kill $(cat nanoclaw.pid)      # stop
    tail -f logs/nanoclaw.log     # logs
    ```

    To get a real service, enable systemd in WSL (`/etc/wsl.conf` → `[boot] systemd=true`, then `wsl --shutdown` from PowerShell) and re-run `pnpm run setup -- --step service`.
  </Tab>
</Tabs>

## 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.

<Tree>
  <Tree.Folder name="nanoclaw" defaultOpen>
    <Tree.Folder name="src" />

    <Tree.Folder name="dist" />

    <Tree.Folder name="container">
      <Tree.File name="Dockerfile" />

      <Tree.File name="build.sh" />

      <Tree.File name="CLAUDE.md" />

      <Tree.Folder name="agent-runner" />
    </Tree.Folder>

    <Tree.Folder name="groups" defaultOpen>
      <Tree.Folder name="main" defaultOpen>
        <Tree.File name="instructions.prepend.md" />

        <Tree.Folder name="memory" />

        <Tree.File name="CLAUDE.md" />

        <Tree.File name="container.json" />
      </Tree.Folder>
    </Tree.Folder>

    <Tree.Folder name="data" defaultOpen>
      <Tree.File name="v2.db" />

      <Tree.Folder name="v2-sessions" defaultOpen>
        <Tree.Folder name="{agent_group_id}" defaultOpen>
          <Tree.Folder name="{session_id}">
            <Tree.File name="inbound.db" />

            <Tree.File name="outbound.db" />

            <Tree.File name=".heartbeat" />
          </Tree.Folder>

          <Tree.Folder name=".claude-shared" />
        </Tree.Folder>
      </Tree.Folder>

      <Tree.Folder name="env">
        <Tree.File name="env" />
      </Tree.Folder>

      <Tree.Folder name="ipc" />

      <Tree.File name="cli.sock" />
    </Tree.Folder>

    <Tree.Folder name="logs">
      <Tree.File name="nanoclaw.log" />

      <Tree.File name="nanoclaw.error.log" />

      <Tree.File name="setup.log" />

      <Tree.Folder name="setup-steps" />
    </Tree.Folder>

    <Tree.Folder name="bin">
      <Tree.File name="ncl" />
    </Tree.Folder>

    <Tree.File name=".env" />

    <Tree.File name="nanoclaw.sh" />
  </Tree.Folder>
</Tree>

The highlights:

| Path                                                  | Purpose                                                                                                                      |
| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `groups/<folder>/instructions.prepend.md`             | The group's standing instructions and persona — this is the file you edit.                                                   |
| `groups/<folder>/memory/`                             | The agent's [durable memory tree](/concepts/agent-memory), scaffolded at boot and shared by every provider.                  |
| `groups/<folder>/CLAUDE.md`                           | Regenerated at every container spawn from the shared base plus enabled skills. Don't edit it — your changes get overwritten. |
| `groups/<folder>/container.json`                      | Per-group container overrides.                                                                                               |
| `container/CLAUDE.md`                                 | Shared base instructions for all agents, mounted read-only into every container.                                             |
| `data/v2.db`                                          | Host state database (registered groups, tasks, sessions).                                                                    |
| `data/v2-sessions/`                                   | Per-session message queues — `inbound.db` (host writes) and `outbound.db` (container writes).                                |
| `data/env/env`                                        | Container-mounted copy of `.env`, synced by setup.                                                                           |
| `~/.config/nanoclaw/mount-allowlist.json`             | Which host directories agents may mount. Never mounted into containers.                                                      |
| `~/.config/nanoclaw/sender-allowlist.json`            | Optional per-channel sender access control.                                                                                  |
| `~/.local/bin/ncl`                                    | Symlink to `bin/ncl` so the CLI works from any directory.                                                                    |
| `~/Library/LaunchAgents/com.nanoclaw-v2-<slug>.plist` | launchd service (macOS).                                                                                                     |
| `~/.config/systemd/user/nanoclaw-v2-<slug>.service`   | systemd user service (Linux).                                                                                                |

## Next steps

<CardGroup cols={2}>
  <Card title="Quick start" icon="bolt" href="/quickstart">
    The one-command flow and the wizard, step by step.
  </Card>

  <Card title="Architecture" icon="diagram-project" href="/concepts/architecture">
    How the host, containers, and the two-DB session model fit together.
  </Card>

  <Card title="The ncl CLI" icon="terminal" href="/operate/ncl-cli">
    Inspect agents, groups, and sessions from the command line.
  </Card>

  <Card title="Troubleshooting" icon="life-ring" href="/operate/troubleshooting">
    Setup failures start at `logs/setup.log`; runtime issues at `logs/nanoclaw.log`.
  </Card>
</CardGroup>
