> ## 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 | 22 or newer on the host (`engines` in `package.json`). Installed or upgraded for you if needed. |
| 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 22+. |
| 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 at the pinned gateway version (1.42.0), or reuses an existing healthy OneCLI instance if it finds one. A reused instance is not version-checked; see [upgrading](/operate/upgrading). OneCLI 1.43 and later are not supported yet. |
| Bun 1.4.0 | 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 or upgrades to Node 22 via `setup/install-node.sh` if Node 22+ 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, [credential gateway](/operate/gateways) install (OneCLI by default; Advanced setup can pick Iron Proxy), provider auth, service install, and channel pairing happen. [Quick start](/quickstart) walks through every wizard step.

<img className="block dark:hidden" src="https://mintcdn.com/qwibitai-nanoclaw-8/eaEEYcmCdIZ6Tipx/images/diagrams/installation-light.svg?fit=max&auto=format&n=eaEEYcmCdIZ6Tipx&q=85&s=d7c168dd200d62197c6be92c99b3577a" alt="The three installer stages: nanoclaw.sh pre-flight in bash, setup.sh bootstrap installing Node and dependencies, then the pnpm run setup:auto wizard where the real setup happens" width="1320" height="648" data-path="images/diagrams/installation-light.svg" />

<img className="hidden dark:block" src="https://mintcdn.com/qwibitai-nanoclaw-8/eaEEYcmCdIZ6Tipx/images/diagrams/installation-dark.svg?fit=max&auto=format&n=eaEEYcmCdIZ6Tipx&q=85&s=95e2c6e73bf283b8e54022fad5b94123" alt="The three installer stages: nanoclaw.sh pre-flight in bash, setup.sh bootstrap installing Node and dependencies, then the pnpm run setup:auto wizard where the real setup happens" width="1320" height="648" data-path="images/diagrams/installation-dark.svg" />

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 22+ and pnpm. The wizard compiles TypeScript with `tsc` and the service runs `node dist/index.js`.
* **Agent container**: Bun 1.4.0 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 defaults to the first 8 hex chars of `sha1(projectRoot)`. `NANOCLAW_INSTALL_ID` in the process environment overrides it with a stable ID: 1–32 lowercase letters, digits, underscores, or hyphens, starting with a letter or digit. Use a distinct ID for each install; sharing an ID also shares the scope used for images, services, and container cleanup.

The container step fetches a pre-built image by default: 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. Building locally is the explicit **Build it here** choice (and the fallback when the pin or its login script is missing, sign-in doesn't complete, or the provider isn't claude). 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 runtime shipped in this repository.** Session lifecycle operations live behind the driver interface in `src/drivers/`. `NANOCLAW_RUNTIME_DRIVER` selects a registered driver and defaults to `docker`; an unknown driver fails instead of falling back. `src/container-runtime.ts` retains the Docker binary constant for non-session operations such as image builds.

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`, `pair-dial`, `groups`, `whatsapp-auth`, `signal-auth`, `mounts`, `service`, `verify`, `provider-auth`, `cli-agent`, `registry`, `portal`, `registry-reconcile`, `gateway`, `gateway-auth`.

### 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`, `gateway`, `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`) |
| `NANOCLAW_AGENT_PROVIDER` | Preselect the agent runtime (for example `claude`) and skip the provider question |
| `NANOCLAW_GATEWAY_PROVIDER` | Select the credential gateway (`onecli` by default, or `iron-proxy`) without asking |

For Anthropic-compatible custom endpoints, set `ANTHROPIC_BASE_URL` in `.env` — the host passes it through to the agent SDK inside the container.

## Install on Proxmox VE

On a Proxmox VE host, a helper script creates a container and installs NanoClaw in it. The NanoClaw team maintains it on its own fork, [glifocat/nanoclaw-proxmox](https://github.com/glifocat/nanoclaw-proxmox). It uses the community-scripts engine but is not part of community-scripts, so report problems to NanoClaw, not to that project.

Run this in the Proxmox VE host shell as root:

```bash theme={null}
bash -c "$(curl -fsSL https://raw.githubusercontent.com/glifocat/nanoclaw-proxmox/nanoclaw-helper-v2.2/ct/nanoclaw.sh)"
```

It supports Proxmox VE 8.0–8.9 and 9.0–9.2 and refuses other versions.

<Warning>
  If newer container packages (`pve-container`, `lxc-pve`) are available for the host, the helper first offers to upgrade them. Accepting runs `apt-get upgrade -y` on the host, which upgrades every host package, not just those two. Decline it if you manage host updates yourself.
</Warning>

The helper creates:

* **An unprivileged Debian 13 LXC** with 2 cores, 8 GiB RAM and a 40 GiB disk by default. The helper's advanced settings let you change them. Nesting and keyctl are enabled so Docker can run inside the container.
* **The runtime:** Docker, Node.js 22 and pnpm.
* **NanoClaw itself:** the latest release in `/home/nanoclaw/nanoclaw`, the home folder of a dedicated `nanoclaw` account that builds and owns it instead of root. The checkout is a git repository at the release tag, so skills and the updater work as they do on any other install.

At the end, an interactive run asks **Start NanoClaw setup now?** Answer `y` to open the [setup wizard](/quickstart) as the `nanoclaw` user; it takes care of sign-in, the OneCLI vault, the agent image and the service. If you skip it, the helper prints the command to start the wizard from the host later:

```bash theme={null}
pct exec <CTID> --keep-env 0 -- machinectl shell nanoclaw@ /usr/bin/bash -lc 'cd /home/nanoclaw/nanoclaw && exec bash nanoclaw.sh'
```

**Updating:** open the container's shell (`pct enter <CTID>`) and run `update`. It checks for a newer NanoClaw release and applies it through NanoClaw's own [update transaction](/operate/upgrading). When a release lists breaking changes that need manual steps, the helper does not apply it: it prints those steps, keeps the running version, and you finish the update with `/update-nanoclaw` from `/home/nanoclaw/nanoclaw` as the `nanoclaw` user.

The link is pinned to the `nanoclaw-helper-v2.2` tag, and so are the install script and the community-scripts engine it loads. A container's `update` command keeps using that helper version. It still installs new NanoClaw releases. Containers created with helper v2.1 or earlier keep NanoClaw in `/opt/nanoclaw`.

For help, [open an issue](https://github.com/nanocoai/nanoclaw/issues/new/choose) on the NanoClaw repository and mention Proxmox VE, or ask in [Discord](https://discord.gg/VDdww8qS42).

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

If you reach the internet through an outbound proxy, the service step reads `HTTPS_PROXY` and `HTTP_PROXY` (`ALL_PROXY` is used as a fallback for either) and `NO_PROXY` from your setup shell or `.env` and passes them to the service. Loopback addresses are always added to `NO_PROXY`. This needs Node 22.21+, 24.5+ or 25+: on an older Node the wizard warns that the proxy is ignored and NanoClaw connects directly. Only `http://` and `https://` proxy URLs are used. The values are kept in an owner-only `data/service-proxy.env` file (launchd keeps them in the owner-only plist), because a proxy URL can contain a password.

<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

Most application state lives inside the checkout. Security allowlists and registry account state live in `~/.config/nanoclaw/`; service definitions, Docker state, command symlinks, and [update transaction backups](/operate/upgrading) also live outside it.

<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="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` | Generated projection of the group's database-backed container configuration. Edit it through `ncl`, not this file. |
| `container/CLAUDE.md` | Shared base instructions inlined into the generated group `CLAUDE.md`. |
| `data/v2.db` | Host state database (groups, sessions, wirings, users, and configuration). |
| `data/v2-sessions/` | Per-session message queues and scheduled-task occurrences — `inbound.db` (host writes) and `outbound.db` (container writes). |
| `~/.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>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.