Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions docs-site/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# NanoClaw docs portal (staged v2 MVP)

This directory is a self-contained [Mintlify](https://mintlify.com) project that holds the **staged v2 documentation portal** for NanoClaw. It is deliberately scoped to an MVP foundation while the v2 docs catch up — it does not replace the existing docs at the repository root.

## Scope (PR 1)

- Mintlify shell and config (`docs.json`)
- MVP foundation pages only:
- `introduction.mdx`
- `quickstart.mdx`
- `migration-from-v1.mdx`
- `architecture.mdx` — architecture overview
- `database-and-sessions.mdx` — database and session model
- `changelog.mdx` — changelog and versioning

Detailed channel and provider guides are intentionally deferred to later stages.

## Source of truth

Content is tied to NanoClaw v2 source discovery from `qwibitai/nanoclaw`:

- Release tag: `v2.0.54`
- Commit: `a33b1ae`
- Package version: `2.0.54`
- Discovery date: `2026-05-10`

Primary sources used: the v2 `README.md`, `CLAUDE.md`, `CHANGELOG.md`, `docs/db.md` (and the linked `docs/db-central.md` / `docs/db-session.md`), `docs/v1-to-v2-changes.md`, `docs/migration-dev.md`, `docs/architecture.md`, `docs/isolation-model.md`, `docs/build-and-runtime.md`, `migrate-v2.sh`, `nanoclaw.sh`, `package.json`, `src/db/schema.ts`, `src/db/migrations/014-container-configs.ts`, `src/db/migrations/015-cli-scope.ts`, `src/container-config.ts`, and `src/cli/`.

Pages that make version-sensitive claims carry a **Source status** callout near the top with the release tag, commit, package version, date, and the specific source files checked. When the upstream tag or version moves, re-verify those pages and update the callouts.

Avoid reintroducing stale v1 claims here — the only place v1 behavior appears is in explicit migration warnings on `migration-from-v1.mdx` and `changelog.mdx`.

## Local development

Install the Mintlify CLI once (`npm i -g mint`), then from this directory:

```bash
mint dev # local preview at http://localhost:3000
mint validate # strict build validation
mint broken-links # check internal links
```

`mint validate` and `mint broken-links` must be run from the directory that contains `docs.json` — that is, this `docs-site/` directory, not the repository root.

## Relationship to the root docs

The existing production docs site lives at the repository root (`../docs.json` and the content directories beside it). This `docs-site/` portal is staged separately so it can be reviewed and iterated without disturbing what is currently deployed. Promotion/merge strategy is out of scope for PR 1.
146 changes: 146 additions & 0 deletions docs-site/architecture.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
---
title: "Architecture overview"
description: "How NanoClaw v2 fits together — the host process, per-session containers, the entity model, and the message flow."
keywords: ["NanoClaw architecture", "entity model", "agent groups", "sessions", "container runtime"]
---

NanoClaw v2 is a single Node host process that orchestrates per-session agent containers. Messages route through an explicit entity model and the host and container exchange data only through two SQLite files per session. There is no IPC, no file watcher, and no stdin piping between them — everything is a message.

<Note>
**For: builders and operators.** Read this page when you need to choose an isolation level, explain where a message goes, or debug routing. If you only want a first assistant, start with [Quickstart](/quickstart).
</Note>

<Info>
**Source status** — Verified against [`qwibitai/nanoclaw`](https://github.com/qwibitai/nanoclaw) at tag `v2.0.54` (commit `a33b1ae`), package version `2.0.54`, on 2026-05-10. Primary sources checked: `README.md`, `CLAUDE.md`, `docs/architecture.md`, `docs/isolation-model.md`, `docs/build-and-runtime.md`, `docs/db-central.md`, `src/db/schema.ts`, `src/router.ts`, `src/container-config.ts`, `src/cli/`.
</Info>

## Message flow

```text
messaging apps → host process (router) → inbound.db → container (Bun, Claude Agent SDK) → outbound.db → host process (delivery) → messaging apps
```

```mermaid
flowchart LR
A[Messaging app] -->|platform event| B[Channel adapter]
B -->|platform channel + thread IDs, triggered?| C[Host router]
C -->|resolve user → messaging group → agent group → session| D[(inbound.db)]
C -->|wake| E[Agent container<br/>Bun + Claude Agent SDK]
D -->|poll| E
E -->|write response| F[(outbound.db)]
F -->|poll| G[Host delivery]
G -->|deliver| B
B --> A
```

1. A channel adapter receives a platform event, decides whether it's triggered, and reports the platform channel ID, optional thread ID, and trigger result. The adapter never sees agent group IDs or session IDs.
2. The host router resolves that to a session through the entity model and writes the message into the session's `inbound.db`, then wakes the container.
3. The agent-runner inside the container polls `inbound.db`, runs Claude, and writes responses to `outbound.db`.
4. The host's delivery loop polls `outbound.db`, looks up where the response goes, and sends it back through the channel adapter. A 60-second host sweep handles stale-session detection, due-task wakeups, and recurrence.

Check warning on line 39 in docs-site/architecture.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/architecture.mdx#L39

Did you really mean 'wakeups'?

## The entity model

v2 separates messaging surfaces from agent identities and wires them together explicitly. In product terms: **messaging groups are chats/channels, agent groups are workspaces/identities, and wirings connect them.**

Check warning on line 43 in docs-site/architecture.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/architecture.mdx#L43

Did you really mean 'wirings'?

```text
users (id "<channel_type>:<handle>", kind, display_name)
└─ user_roles (user_id, role ∈ {owner, admin}, agent_group_id nullable) — owner is global; admin is global or scoped
└─ agent_group_members (user_id, agent_group_id) — "known" membership gate

agent_groups (workspace, memory, CLAUDE.md, personality)
container_configs (provider, model, effort, packages, MCP servers, mounts, skills, cli_scope)
↕ many-to-many via messaging_group_agents
(engage_mode, engage_pattern, sender_scope, ignored_message_policy, session_mode, priority)
messaging_groups (one chat/channel on one platform; channel_type, platform_id, unknown_sender_policy)

sessions (agent_group_id + messaging_group_id + thread_id → per-session container)
```

Key consequences:

- **One agent can answer on many chats, and one chat can fan out to many agents.** v1 could do neither — it had one flat `registered_groups` table where a chat mapped to exactly one folder.
- **Privilege is user-level, not channel-level.** Roles live in `user_roles` (owner is always global; admin can be global or scoped to an agent group). The old "main channel = admin" concept is gone. The router-side admin command gate queries `user_roles` directly — there is no environment variable for admin user IDs.
- **Engagement is decomposed into orthogonal columns** on the `messaging_group_agents` wiring, replacing v1's opaque `trigger_pattern` regex:
- `engage_mode` — `mention` (default), `pattern`, or `mention-sticky`
- `engage_pattern` — regex source, required when `engage_mode='pattern'`; `'.'` means "match every message"
- `sender_scope` — `all` (default) or `known`
- `ignored_message_policy` — `drop` (default) or `accumulate`
- `session_mode` and `priority`
- **Unknown senders** are governed per messaging group by `unknown_sender_policy` (`strict`, `request_approval`, or `public`).

## Agent groups, sessions, and containers

An **agent group** has its own filesystem under `groups/<folder>/` — `CLAUDE.md`, skills, memory, and workspace files. Its runtime config lives in the central DB's `container_configs` table: provider, model, effort, packages, MCP servers, mounts, skills, and `cli_scope`. A materialized `container.json` is written at spawn time for the container runner. A **session** is keyed by `(agent_group_id, messaging_group_id, thread_id)` and gets its own container with that agent group's filesystem mounted and its own pair of session DBs. Multiple sessions can share one agent group (same skills, same memory) while keeping separate conversation contexts.

Check warning on line 73 in docs-site/architecture.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/architecture.mdx#L73

Did you really mean 'DB's'?

Check warning on line 73 in docs-site/architecture.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/architecture.mdx#L73

Did you really mean 'DBs'?

The agent's `CLAUDE.md` is composed at container spawn from a shared base (`.claude-shared.md`, a symlink to the global file), module fragments (`.claude-fragments/*.md`), and per-group `CLAUDE.local.md`. Don't edit the composed `CLAUDE.md` directly.

## Channel isolation — three levels

When you connect a channel, you choose how it relates to your existing agents (see [`docs/isolation-model.md`](https://github.com/qwibitai/nanoclaw/blob/main/docs/isolation-model.md)):

| Level | What's shared | Wiring |
|-------|---------------|--------|
| Separate agent groups | Nothing — different `CLAUDE.md`, memory, workspace, container, conversation | Each messaging group → a different agent group |
| Same agent, separate sessions | Workspace, memory, `CLAUDE.md`, personality; conversations stay independent | Multiple messaging groups → one agent group, `session_mode: 'shared'` |
| Shared session | Everything, including the conversation itself — all channels appear in one thread | Multiple messaging groups → one agent group, `session_mode: 'agent-shared'` |

The decision question: are you okay with any piece of information from one channel being available in the other? If no, use separate agent groups. If yes and the channels should see each other's messages, use a shared session. If yes but the conversations should stay independent, use the same agent with separate sessions.

## Channels and providers are skill-installed

Trunk ships the registry and infrastructure, not specific channel adapters or non-default agent providers:

- **`channels` branch** — Discord, Slack, Telegram, WhatsApp, Teams, Linear, GitHub, iMessage, Webex, Resend, Matrix, Google Chat, WhatsApp Cloud, plus their setup steps. Installed via `/add-<channel>` skills.

Check warning on line 93 in docs-site/architecture.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/architecture.mdx#L93

Did you really mean 'iMessage'?

Check warning on line 93 in docs-site/architecture.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/architecture.mdx#L93

Did you really mean 'Webex'?
- **`providers` branch** — OpenCode and other non-default agent providers. Installed via `/add-opencode` (and `/add-codex`, `/add-ollama-provider`).

Each `/add-<name>` skill is idempotent: fetch the branch, copy the module(s) into the standard paths, append a self-registration import, install pinned dependencies, and build. Credentials are managed by OneCLI's Agent Vault — secrets are injected into per-agent containers at request time and never passed via env vars or chat context.

The `ncl` admin CLI manages live state in the central DB. In v2.0.54, per-group runtime settings are updated with commands such as `ncl groups config update --model <model> --effort <level>` and applied on an explicit `ncl groups restart`.

For exact CLI flags, defaults, aliases, and command-specific examples, use the help bundled with your installed checkout instead of copying reference text from this portal:

```bash
pnpm run ncl -- help
pnpm run ncl -- groups config --help
pnpm run ncl -- groups restart --help
```

## Runtime split: Node host, Bun container

The host runs on **Node 22 + pnpm**; the agent container runs on **Bun**. They share no modules — the only interface is the two session DBs — which is what lets them use different runtimes cleanly.

Check warning on line 110 in docs-site/architecture.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/architecture.mdx#L110

Did you really mean 'DBs'?

Check warning on line 110 in docs-site/architecture.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/architecture.mdx#L110

Did you really mean 'runtimes'?

- **Host stays on Node** because some channel adapters (notably WhatsApp's Baileys) depend on native bindings and a long-tested HTTP/WebSocket stack.
- **Container runs Bun** because `bun:sqlite` is built in (no per-image native compile of `better-sqlite3`), source runs directly (no `tsc` build step at image build or session wake), and `bun install` is much faster.
- **Lockfiles:** the host uses `pnpm-lock.yaml` with a `minimumReleaseAge` supply-chain policy; the agent-runner uses `container/agent-runner/bun.lock`. Both are committed; CI and the Dockerfile run `--frozen-lockfile`.

Check warning on line 114 in docs-site/architecture.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/architecture.mdx#L114

Did you really mean 'Lockfiles'?

Check warning on line 114 in docs-site/architecture.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/architecture.mdx#L114

Did you really mean 'Dockerfile'?
- **Tests:** host tests run under vitest (`pnpm test`); agent-runner tests run under `bun:test` (`cd container/agent-runner && bun test`).

Check warning on line 115 in docs-site/architecture.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/architecture.mdx#L115

Did you really mean 'vitest'?

## Key source files

| File | Purpose |
|------|---------|
| `src/index.ts` | Entry point: DB init, migrations, channel adapters, delivery polls, sweep, shutdown |
| `src/router.ts` | Inbound routing: messaging group → agent group → session → `inbound.db` → wake |
| `src/delivery.ts` | Polls `outbound.db`, delivers via adapter, handles system actions |
| `src/host-sweep.ts` | 60-second sweep: `processing_ack` sync, stale detection, due-message wake, recurrence |
| `src/session-manager.ts` | Resolves sessions; opens `inbound.db` / `outbound.db`; manages the heartbeat path |
| `src/container-config.ts` | Reads/writes per-group runtime config from `container_configs`; materializes `container.json` at spawn time |
| `src/container-runner.ts` | Spawns per-agent-group containers, OneCLI credential injection |
| `src/cli/` | `ncl` admin CLI for DB-backed groups, wirings, approvals, sessions, destinations, and config |

Check warning on line 128 in docs-site/architecture.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/architecture.mdx#L128

Did you really mean 'wirings'?
| `src/db/` | Central DB layer — agent groups, messaging groups, sessions, user roles, migrations |
| `src/channels/` | Channel adapter infra; specific adapters are skill-installed from the `channels` branch |
| `src/providers/` | Host-side provider config (`claude` baked in; others via the `providers` branch) |
| `container/agent-runner/` | Bun agent-runner: poll loop, MCP tools, provider abstraction |
| `groups/<folder>/` | Per-agent-group filesystem (`CLAUDE.md`, skills, memory/workspace files); runtime config is DB-backed |

For the full architecture writeup, see [`docs/architecture.md`](https://github.com/qwibitai/nanoclaw/blob/main/docs/architecture.md) in the source repo.

## Related

<Columns cols={2}>
<Card title="Database and sessions" icon="database" href="/database-and-sessions">
The three-DB model, the two-DB session split, and cross-mount rules.
</Card>
<Card title="Migrating from v1" icon="arrow-up-right" href="/migration-from-v1">
Where v1 concepts moved in the v2 entity model.
</Card>
</Columns>
73 changes: 73 additions & 0 deletions docs-site/changelog.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: "Changelog and versioning"
description: "How NanoClaw versions releases and a condensed changelog focused on the v2.0.0 rewrite."
keywords: ["NanoClaw changelog", "versioning", "v2.0.0", "release notes"]
---

<Info>
**Source status** — Verified against [`qwibitai/nanoclaw`](https://github.com/qwibitai/nanoclaw) at tag `v2.0.54` (commit `a33b1ae`), package version `2.0.54`, on 2026-05-10. Primary sources checked: `CHANGELOG.md`, `package.json`, `src/db/schema.ts`, `src/db/migrations/014-container-configs.ts`, `src/db/migrations/015-cli-scope.ts`, `src/cli/`.
</Info>

## Versioning

The version of record for this staged portal is release tag **`v2.0.54`** (commit `a33b1ae`), whose `package.json` version is **`2.0.54`**. The 2.x line is the ground-up rewrite; releases follow semantic versioning, with breaking changes called out explicitly in `CHANGELOG.md`.

`CHANGELOG.md` in the source repo is the canonical list of notable and breaking changes. It is intentionally sparse — patch releases that only touch internals may not get an entry. For the full per-version history, use release tags and the git history of `package.json`.

<Note>
This staged portal is intentionally pinned to `v2.0.54`, not a moving `main` snapshot.
</Note>

## v2.0.54 — current staged source

The latest verified source for this staged portal is `v2.0.54`:

- **Per-group model and effort overrides.** Agent groups can run a specific Claude model and effort level, managed with `ncl groups config update --model <model> --effort <level>`. When unset, they inherit the host-configured defaults.
- **Claude Code 2.1.128 in containers.** The container image bumps `claude-code` from 2.1.116 to 2.1.128.
- **CLI help polish.** `ncl groups config` and `ncl groups restart` have clearer help text.

Recent 2.0.x releases also added the admin `ncl` CLI, moved per-agent-group runtime config into the central `container_configs` table, added per-group `cli_scope`, and made group restarts explicit via `ncl groups restart` with race-free `on_wake` messages.

## v2.0.0 — architectural rewrite

NanoClaw v2 is a substantial architectural rewrite. It **cannot be merged into an existing v1 install** — existing forks migrate via `migrate-v2.sh` (see [Migrating from v1](/migration-from-v1)) or replay customizations onto the clean v2 base.

Breaking changes in v2.0.0:

- **New entity model.** Users, roles (owner/admin), messaging groups, and agent groups are tracked as separate entities, wired via `messaging_group_agents`. Privilege is user-level instead of channel-level — the old "main channel = admin" concept is retired.
- **Two-DB session split.** Each session has `inbound.db` (host writes, container reads) and `outbound.db` (container writes, host reads), each with exactly one writer. Replaces the single shared session DB and eliminates cross-mount SQLite contention.
- **Install flow replaced.** `bash nanoclaw.sh` is the new default — a scripted installer that hands off to Claude Code for error recovery and guided decisions. The `/setup` Claude-guided skill still works as an alternative.
- **Channels moved to the `channels` branch.** Trunk no longer ships Discord, Slack, Telegram, WhatsApp, iMessage, Teams, Linear, GitHub, WeChat, Matrix, Google Chat, Webex, Resend, or WhatsApp Cloud. Install them per fork via `/add-<channel>` skills.

Check warning on line 40 in docs-site/changelog.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/changelog.mdx#L40

Did you really mean 'iMessage'?

Check warning on line 40 in docs-site/changelog.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/changelog.mdx#L40

Did you really mean 'Webex'?
- **Alternative providers moved to the `providers` branch.** OpenCode, Codex, and Ollama install via `/add-opencode`, `/add-codex`, `/add-ollama-provider`. Claude remains the default provider baked into trunk.

Check warning on line 41 in docs-site/changelog.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/changelog.mdx#L41

Did you really mean 'Ollama'?
- **Three-level channel isolation.** Wire channels to their own agent, share an agent with independent conversations (`session_mode: 'shared'`), or merge channels into one shared session (`session_mode: 'agent-shared'`).
- **Apple Container removed from default setup.** Still available as an opt-in via `/convert-to-apple-container`.

Other notable changes:

- **Shared-source agent-runner.** Per-group `agent-runner-src/` overlays are gone; all groups mount the same agent-runner read-only. Per-group customization flows through a composed `CLAUDE.md`.
- **Agent-runner runtime moved from Node to Bun.** The container image is self-contained; the host stays on Node + pnpm.
- **OneCLI Agent Vault is the sole credential path.** Containers never receive raw API keys; credentials are injected at request time.

## After v2.0.0

The 2.0.x line has tracked migration robustness and setup polish — for example, hardware-spec warnings during setup, Telegram BotFather QR pairing, and fixes to the v1 → v2 migration steps (Discord DM resolution, symlink handling, `unknown_sender_policy` reconciliation). See [`CHANGELOG.md`](https://github.com/qwibitai/nanoclaw/blob/main/CHANGELOG.md) for the running list.

## Selected pre-v2 history

For reference, a few notable v1 milestones from `CHANGELOG.md`:

- **1.2.35–1.2.36** — OneCLI Agent Vault replaced the built-in credential proxy; the pino logger was replaced with a built-in logger.

Check warning on line 59 in docs-site/changelog.mdx

View check run for this annotation

Mintlify / Mintlify Validation (qwibitai-nanoclaw-8) - vale-spellcheck

docs-site/changelog.mdx#L59

Did you really mean 'pino'?
- **1.2.13** — Skills became git branches merged via `git merge`; Docker Sandboxes support added.
- **1.2.0** — WhatsApp removed from core and made a skill (`/add-whatsapp`); channel registry with startup self-registration.
- **1.1.4** — Third-party model support; `/update-nanoclaw` skill for syncing with upstream.

## Related

<Columns cols={2}>
<Card title="Migrating from v1" icon="arrow-up-right" href="/migration-from-v1">
The full v1 → v2 migration path.
</Card>
<Card title="Architecture overview" icon="network" href="/architecture">
What the v2 rewrite actually changed under the hood.
</Card>
</Columns>
Loading