diff --git a/docs-site/README.md b/docs-site/README.md new file mode 100644 index 0000000..a55292a --- /dev/null +++ b/docs-site/README.md @@ -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. diff --git a/docs-site/architecture.mdx b/docs-site/architecture.mdx new file mode 100644 index 0000000..ba96742 --- /dev/null +++ b/docs-site/architecture.mdx @@ -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. + + +**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). + + + +**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/`. + + +## 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
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. + +## 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.** + +```text +users (id ":", 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//` — `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. + +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-` skills. +- **`providers` branch** — OpenCode and other non-default agent providers. Installed via `/add-opencode` (and `/add-codex`, `/add-ollama-provider`). + +Each `/add-` 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 --effort ` 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. + +- **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`. +- **Tests:** host tests run under vitest (`pnpm test`); agent-runner tests run under `bun:test` (`cd container/agent-runner && bun test`). + +## 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 | +| `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//` | 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 + + + + The three-DB model, the two-DB session split, and cross-mount rules. + + + Where v1 concepts moved in the v2 entity model. + + diff --git a/docs-site/changelog.mdx b/docs-site/changelog.mdx new file mode 100644 index 0000000..daf1522 --- /dev/null +++ b/docs-site/changelog.mdx @@ -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"] +--- + + +**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/`. + + +## 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`. + + +This staged portal is intentionally pinned to `v2.0.54`, not a moving `main` snapshot. + + +## 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 --effort `. 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-` skills. +- **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. +- **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. +- **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 + + + + The full v1 → v2 migration path. + + + What the v2 rewrite actually changed under the hood. + + diff --git a/docs-site/configure-overview.mdx b/docs-site/configure-overview.mdx new file mode 100644 index 0000000..974089b --- /dev/null +++ b/docs-site/configure-overview.mdx @@ -0,0 +1,105 @@ +--- +title: "Configure agents" +description: "How to wire NanoClaw messaging groups to agent groups without duplicating CLI command reference text." +keywords: ["NanoClaw configuration", "agent groups", "messaging groups", "wirings", "ncl CLI"] +tag: "NEW" +--- + +Configuration in NanoClaw is mostly choosing boundaries: which chat should reach which agent, which users can trigger it, and what that agent can see inside its container. + + +**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: `src/db/schema.ts`, `src/router.ts`, `src/session-manager.ts`, `src/cli/`, `docs/isolation-model.md`, and `docs/db.md`. + + +## For: tinkerers and builders + +Use this page when you are adding a channel, splitting assistants by purpose, changing model/effort settings, or deciding whether two chats should share memory. For the broader customization path, start with [Tinker/customize](/tinker-customize). + + +This page explains what to decide. It does not duplicate every CLI flag. For exact command syntax on your installed version, run `pnpm run ncl -- help` and the relevant subcommand help. + + +## The four terms to keep straight + +| Term | Plain meaning | Source-level shape | +|------|---------------|--------------------| +| User | A person or platform identity that sends messages | `users`, `user_roles`, `agent_group_members` | +| Messaging group | One chat, channel, DM, room, or threadable platform surface | `messaging_groups` with `channel_type`, `platform_id`, `unknown_sender_policy` | +| Agent group | One assistant identity and workspace | `agent_groups` plus `container_configs` and files under `groups//` | +| Wiring | The rule that connects a messaging group to an agent group | `messaging_group_agents` with engagement, sender, session, and priority fields | + + +A messaging group is where messages come from. An agent group is the workspace and identity that answers. A wiring is the permission and trigger rule between them. + + +## Common configuration decisions + +### 1. Should this chat get a new agent? + +Choose a **separate agent group** when the chat should have different memory, instructions, files, mounts, credentials, or model settings. This is the safest default for work/personal or customer/team boundaries. + +Choose the **same agent group with separate sessions** when you want the same assistant personality and workspace, but independent conversations per chat. + +Choose an **agent-shared session** only when messages from multiple channels should intentionally appear in one shared conversation. + +### 2. Who can trigger the agent? + +The wiring controls engagement: + +- `engage_mode`: mention, regex pattern, or mention-sticky behavior +- `engage_pattern`: regex source when pattern mode is used +- `sender_scope`: all senders or only known members +- `ignored_message_policy`: drop ignored messages or accumulate them for later context +- `session_mode`: separate chat session or agent-shared conversation +- `priority`: ordering when several agents can answer + +Avoid old v1 wording such as `trigger_rules` as the canonical concept. In v2, engagement is stored as columns on `messaging_group_agents`. + +### 3. What can the agent see? + +Agent groups own the container-facing workspace: instructions, memory, skills, package and MCP-server config, mounts, provider/model/effort settings, and CLI scope. The container only sees what that group is configured to expose. + + +Sharing an agent group means sharing its workspace and memory. If two channels must not leak context into each other, use separate agent groups rather than relying on prompt instructions. + + +## CLI help boundary + +Docs should teach the model and the workflow. CLI help should remain the command reference. + +Use CLI help for: + +- exact syntax, flags, defaults, and aliases +- fast-changing command lists +- command-specific examples tied to the installed version + +Use these docs for: + +- why to create a separate agent group versus a shared session +- how messaging groups differ from agent groups +- which isolation level matches a use case +- security and operational tradeoffs + +Useful entry points: + +```bash +pnpm run ncl -- help +pnpm run ncl -- groups --help +pnpm run ncl -- groups config --help +pnpm run ncl -- wirings --help +pnpm run ncl -- sessions --help +``` + +## Related + + + + Source-verified message flow and entity model. + + + Channels, providers, skills, and fork-level changes. + + + Runtime boundaries for teams, customers, credentials, and mounts. + + diff --git a/docs-site/contribute-overview.mdx b/docs-site/contribute-overview.mdx new file mode 100644 index 0000000..80c9e63 --- /dev/null +++ b/docs-site/contribute-overview.mdx @@ -0,0 +1,94 @@ +--- +title: "Contribute" +description: "A compact contributor path for NanoClaw v2: codebase map, architecture invariants, skills, tests, and PR boundaries." +keywords: ["NanoClaw contribute", "codebase", "skills", "tests", "architecture"] +tag: "NEW" +--- + +Contributing to NanoClaw starts with the shape of the system. It is one Node host, per-session Bun containers, and SQLite files with strict writer ownership. Most good changes keep that shape obvious. + + +**Source status** — Verified against [`qwibitai/nanoclaw`](https://github.com/qwibitai/nanoclaw) at source branch `main` (commit `e0e4f01`) and docs branch staged for `v2.0.54`. Primary sources checked: `README.md`, `CONTRIBUTING.md`, `CLAUDE.md`, `docs/skills-as-branches.md`, `docs/build-and-runtime.md`, `docs/agent-runner-details.md`, `.github/workflows/ci.yml`, `package.json`, and `container/agent-runner/package.json`. + + +## Contributor stance + +NanoClaw favors inspectable code over extension frameworks. Before adding a new abstraction, ask whether a small skill, page, adapter, or fork-level change would be clearer. + +Good first contributions: + +- fix docs that still describe v1 behavior +- improve generated CLI help metadata instead of duplicating command tables in docs +- tighten tests around routing, sessions, delivery, or container startup +- add or repair one skill installer +- make an architecture invariant easier to see in code + +Avoid broad rewrites that touch routing, database writes, channels, delivery, and container startup at once. The pieces are intentionally small, but they are tightly coupled. + +## Codebase map + +| Area | Files to start with | What to preserve | +|------|---------------------|------------------| +| Host entrypoint | `src/index.ts` | migrations, channel startup, sweep, delivery loop | +| Routing | `src/router.ts` | user → messaging group → wiring → agent group → session | +| Session files | `src/session-manager.ts` | host writes `inbound.db`; container writes `outbound.db` | +| Delivery | `src/delivery.ts` | host reads outbound and sends through adapters | +| Runtime config | `src/container-config.ts`, `src/container-runner.ts` | per-group config, mounts, provider settings, Agent Vault injection | +| Agent runner | `container/agent-runner/` | Bun runtime, provider query, MCP tools, outbound writes | +| Skills | `container/skills/`, skill branches | focused changes copied into a fork | +| Docs | `docs/`, `docs-site/` | code first, then `CLAUDE.md`, then source docs | + +## Load-bearing invariants + +- **Single writer per SQLite DB.** Host writes central DB and `inbound.db`; container writes `outbound.db`. +- **No v1 IPC path.** `data/ipc` is obsolete. Session DBs are the boundary. +- **Heartbeat is file mtime.** `.heartbeat` is touched by the container; it is not a DB write. +- **Messaging groups are not agent groups.** Messaging groups are chats. Agent groups are identities/workspaces. Wirings connect them. +- **Skills over features.** Add focused skills before growing trunk. +- **Credentials are authority.** Use OneCLI Agent Vault policy; do not pass raw secrets through prompts, broad env vars, or docs examples. + +## Validate before a PR + +Run the smallest checks that cover the files you changed, then the standard gates before opening or updating a PR: + +```bash +pnpm install --frozen-lockfile +pnpm run typecheck +pnpm run build +pnpm run format:check +pnpm test + +cd container/agent-runner +bun install +bun run typecheck +bun test +``` + +Docs-only changes in this portal should also pass: + +```bash +cd docs-site +mint validate +mint broken-links +``` + + +This page names the checks so contributors know the workflow. It is not a replacement for package scripts, CI config, or command help in the checked-out version. + + +## Related + + + + The message flow and entity model every code change should respect. + + + The three-DB model and single-writer rule. + + + Skills and fork-level changes before upstream contributions. + + + Source-status notes and release context. + + diff --git a/docs-site/database-and-sessions.mdx b/docs-site/database-and-sessions.mdx new file mode 100644 index 0000000..41e6eb7 --- /dev/null +++ b/docs-site/database-and-sessions.mdx @@ -0,0 +1,110 @@ +--- +title: "Database and sessions" +description: "NanoClaw v2's three-database model, the two-DB session split, sequence parity, and the cross-mount visibility rules." +keywords: ["NanoClaw database", "session model", "SQLite", "inbound.db", "outbound.db", "central DB"] +--- + +NanoClaw v2 stores state in **three kinds of SQLite database**, all on the host filesystem. Every database file has exactly one writer — that single-writer rule is what keeps SQLite locking sane across the Docker (or Apple Container) mount boundary. + + +**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: `docs/db.md`, `docs/db-central.md`, `docs/db-session.md`, `CLAUDE.md`, `src/db/schema.ts`, `src/session-manager.ts`, `src/db/migrations/014-container-configs.ts`, `src/db/migrations/015-cli-scope.ts`. + + +## The three databases + +| Database | Location | Writer | Readers | Purpose | +|----------|----------|--------|---------|---------| +| Central | `data/v2.db` | host | host | Identity, permissions, routing, wiring — the admin plane | +| Session inbound | `data/v2-sessions///inbound.db` | host | host (sync), container (read-only) | Host → container messages plus routing projections | +| Session outbound | `data/v2-sessions///outbound.db` | container | host (poll), container | Container → host messages plus processing status | + +**Single-writer rule.** The host writes the central DB and every `inbound.db`; the container writes only its own `outbound.db`. No file is written from both sides of the mount. + +**Everything is a message.** There is no IPC, stdin piping, or file watcher between host and container. The two session DBs are the only IO surface. Liveness is a file `touch` on `.heartbeat`, not a DB write. + +## Database layout + +```text +data/ + v2.db ← CENTRAL (host ↔ host) + v2-sessions/ + / + .claude-shared/ ← shared Claude state for the agent group + / + inbound.db ← host writes, container reads (read-only mount) + outbound.db ← container writes, host reads (read-only open) + .heartbeat ← mtime touched by container + inbox// ← decoded user attachments + outbox// ← attachments the agent produced +``` + +Path helpers — `sessionDir()`, `inboundDbPath()`, `outboundDbPath()`, `heartbeatPath()` — all live in `src/session-manager.ts`. A session is keyed by `(agent_group_id, messaging_group_id, thread_id)` and is created on demand. + +## What lives where + +| Kind of data | Where | Why | +|--------------|-------|-----| +| Identities, roles, memberships | central | Stable, cross-session, rarely written | +| Channel wiring and routing rules | central | The admin plane | +| Per-agent-group runtime config | central `container_configs` | Provider/model/effort, packages, MCP servers, mounts, skills, and `cli_scope` need admin visibility and CLI updates | +| Session registry (ids, status) | central | The host orchestrates session lifecycle | +| Approvals, pending sender approvals, and pending questions | central | Survive container restarts; admin-visible | +| Dropped-message audit | central | Global ops view | +| Inbound messages, retry state, scheduled tasks | session `inbound.db` | Per-session workload; the host is sole writer | +| Outbound messages, agent session state | session `outbound.db` | The container is sole writer; the host polls | +| Delivery outcome (`delivered`) | session `inbound.db` | Host writes on success; container reads it for edit/reaction targeting | +| Processing status (`processing_ack`) | session `outbound.db` | The container can't write to `inbound.db`, so it acks via the reverse channel | + +Heuristic: if the value is a message, a routing projection, or a runtime ack, it goes per-session. Everything else is central. Scheduled tasks are `messages_in` rows with `kind='task'` in a session's `inbound.db` — `process_after` (ISO8601) drives the wakeup, `recurrence` holds a cron string (`NULL` for one-shot), and `series_id` groups recurring occurrences. + +## The two-DB session split + +Each session owns two files: + +- **`inbound.db`** — host writes, container reads (mounted read-only). Tables: `messages_in`, `delivered`, `destinations` (a projection of the central `agent_destinations` ACL), `session_routing` (the default outbound target). +- **`outbound.db`** — container writes, host reads. Tables: `messages_out`, `processing_ack`, `session_state`, `container_state`. + +The schemas are the `INBOUND_SCHEMA` and `OUTBOUND_SCHEMA` constants in `src/db/schema.ts`; `ensureSchema()` in `src/session-manager.ts` creates both files when a session folder is provisioned. + +Central DB schemas are created by numbered migrations. As of `v2.0.54`, the central DB includes `container_configs` for per-agent-group runtime settings and `pending_sender_approvals` for deduplicated unknown-sender approval cards. Session DB schemas are created lazily from `src/db/schema.ts`. + +### Sequence parity + +`messages_in.seq` is always **even** (the host assigns it); `messages_out.seq` is always **odd** (the container assigns it). The two namespaces are disjoint, so the agent can reference any message in the session by `seq` alone, regardless of direction. + +### Projections + +`destinations` and `session_routing` in `inbound.db` are projected from the central DB on every container wake (and again when wiring changes mid-session). This gives the container a fast, local read path for "who am I allowed to send to" and "where do replies go by default" without ever querying across the mount. + +### Fresh-wake messages + +`messages_in.on_wake = 1` marks rows that should only be delivered on a fresh container's first poll. This is used by explicit restarts and self-mod approval flows so a dying container cannot steal a restart/configuration message during its SIGTERM grace period. + +## Cross-mount visibility rules + +Session DBs are bind-mounted into the container, and SQLite's usual assumptions don't hold across that boundary. A few rules are load-bearing — read `src/session-manager.ts` and `container/agent-runner/src/db/connection.ts` before touching DB code: + +- **`journal_mode = DELETE`, not WAL.** WAL's memory-mapped `-shm` file doesn't refresh reliably across the mount; the container can read stale pages. DELETE mode forces each writer to flush the main file. +- **Open-write-close on the host.** Host writes to `inbound.db` open a connection, write, and close it. Keeping a handle open leaves cached pages invisible to the container. +- **Container reads are read-only.** The container opens `inbound.db` with `readonly: true` and never writes. All container → host state goes through `outbound.db`. +- **Heartbeat is a file touch.** `.heartbeat` mtime is the liveness signal, not a DB column — a DB write per heartbeat would serialize behind other writers. +- **Named SQL params in the container keep their prefix.** `bun:sqlite` does not auto-strip `$`/`@`/`:` the way `better-sqlite3` does on the host — use `$name` in both the SQL and the JS object keys. + +## Migrations + +The central DB uses numbered migrations under `src/db/migrations/` (run by `src/db/migrations/index.ts`, tracked in a `schema_version` table). Per-session DBs use `CREATE TABLE IF NOT EXISTS` plus ad-hoc `ALTER TABLE` helpers so older session folders are brought up to schema lazily on open. + +The current staged source includes migrations `014-container-configs.ts` and `015-cli-scope.ts`, which move per-group container settings into the central `container_configs` table and add `cli_scope` (`disabled`, `group`, or `global`) for the in-container `ncl` CLI. + +For the table-by-table reference, see the source docs: [`docs/db.md`](https://github.com/qwibitai/nanoclaw/blob/main/docs/db.md) (overview), [`docs/db-central.md`](https://github.com/qwibitai/nanoclaw/blob/main/docs/db-central.md) (central DB), and [`docs/db-session.md`](https://github.com/qwibitai/nanoclaw/blob/main/docs/db-session.md) (per-session DBs). + +## Related + + + + Where the databases sit in the message flow and the entity model. + + + v1's single `store/messages.db` versus v2's three-DB model. + + diff --git a/docs-site/deploy-overview.mdx b/docs-site/deploy-overview.mdx new file mode 100644 index 0000000..a7f7aa5 --- /dev/null +++ b/docs-site/deploy-overview.mdx @@ -0,0 +1,84 @@ +--- +title: "Deploy and operate" +description: "Operational guidance for running NanoClaw v2: services, databases, containers, credentials, and team isolation." +keywords: ["NanoClaw deployment", "operations", "service", "containers", "Agent Vault", "SQLite"] +tag: "NEW" +--- + +NanoClaw v2 is still one host process, but an operator needs to understand the boundaries around that process: service manager, Docker or another container runtime, SQLite files, OneCLI Agent Vault, and channel credentials. + + +**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`, `docs/build-and-runtime.md`, `docs/db.md`, `docs/isolation-model.md`, `src/session-manager.ts`, `src/container-runner.ts`, and `src/db/schema.ts`. + + +## For: operators, teams, and enterprise evaluators + +Use this page when NanoClaw is serving more than one person, more than one channel, or a long-running business workflow. If you need the security and governance decision path first, read [Operational boundaries](/operational-boundaries). If you are installing a personal assistant for the first time, start with [Quickstart](/quickstart) instead. + +## Operational model + +```text +service manager + → Node host process + → central DB: data/v2.db + → per-session containers + → inbound.db / outbound.db pairs + → channel adapters and OneCLI Agent Vault +``` + +The host owns routing, permissions, migrations, channel adapters, and service lifecycle. Containers run agent sessions and write only their own `outbound.db`. This split is the deployment boundary: back up the host data directory, monitor the host service, and treat containers as replaceable session workers. + +## Isolation choices for teams + +| Need | Recommended shape | +|------|-------------------| +| Separate customers, teams, or departments | Separate agent groups | +| Same assistant across several team chats, but independent conversations | One agent group with `session_mode: 'shared'` per wiring | +| One conversation mirrored across several channels | One agent group with `session_mode: 'agent-shared'` | +| Different model, effort, packages, MCP servers, mounts, or credentials | Separate agent groups or separate runtime config | + + +The safest business boundary is an agent group boundary. Prompt text cannot replace filesystem, memory, credential, and mount isolation. + + +## What to monitor + +- **Host service** — launchd on macOS or systemd user service on Linux. +- **Container runtime** — Docker by default; Apple Container and Docker Sandboxes are opt-in alternatives. +- **Data directory** — `data/v2.db` plus `data/v2-sessions///`. +- **Session liveness** — `.heartbeat` file mtimes are the liveness signal; the host sweep handles stale-session detection and due-task wakeups. +- **Credential path** — OneCLI Agent Vault injects secrets at request time. Containers should not receive raw API keys through chat context or broad environment variables. + +## Backups and upgrades + +Back up the central DB and session folders together when preserving live state. The central DB stores identities, roles, memberships, wirings, approvals, runtime config, and session registry. Session DBs store per-conversation inbound/outbound messages, tasks, delivery state, and agent session state. + +Before upgrading across major behavior changes, read [Changelog and versioning](/changelog). v1 installs must use [Migrating from v1](/migration-from-v1); do not merge v2 into an existing v1 checkout. + +## CLI help boundary + +Operational pages should avoid stale command dumps. Link to the decision and safety context here, then send operators to local help for exact syntax: + +```bash +pnpm run ncl -- help +pnpm run ncl -- approvals --help +pnpm run ncl -- groups config --help +pnpm run ncl -- groups restart --help +pnpm run ncl -- destinations --help +``` + +This keeps the docs focused on what to operate and why, while the installed CLI remains the source of truth for flags and defaults. + +## Related + + + + The three-DB model and cross-mount single-writer rules. + + + Business isolation, credentials, approvals, monitoring, and hard limits. + + + Customize channels, providers, skills, and fork-level behavior. + + diff --git a/docs-site/docs.json b/docs-site/docs.json new file mode 100644 index 0000000..67e3306 --- /dev/null +++ b/docs-site/docs.json @@ -0,0 +1,74 @@ +{ + "$schema": "https://mintlify.com/docs.json", + "theme": "mint", + "name": "NanoClaw", + "description": "Documentation for NanoClaw — a small, isolated AI team you can fork, inspect, and customize.", + "colors": { + "primary": "#2DD4BF", + "light": "#5EEAD4", + "dark": "#14B8A6" + }, + "appearance": { + "default": "dark" + }, + "banner": { + "content": "This is a staged v2 documentation portal — MVP pages only. Detailed channel and provider guides are coming. [Join the Discord](https://discord.gg/VDdww8qS42) for help.", + "dismissible": true + }, + "navbar": { + "primary": { + "type": "github", + "href": "https://github.com/qwibitai/nanoclaw" + } + }, + "footer": { + "socials": { + "github": "https://github.com/qwibitai/nanoclaw", + "discord": "https://discord.gg/VDdww8qS42", + "website": "https://nanoclaw.dev" + } + }, + "search": { + "prompt": "Search NanoClaw docs..." + }, + "navigation": { + "groups": [ + { + "group": "Get it running", + "pages": [ + "introduction", + "quickstart" + ] + }, + { + "group": "Tinker/customize", + "pages": [ + "tinker-customize", + "configure-overview" + ] + }, + { + "group": "Contribute", + "pages": [ + "contribute-overview", + "architecture", + "database-and-sessions" + ] + }, + { + "group": "Business/enterprise", + "pages": [ + "operational-boundaries", + "deploy-overview" + ] + }, + { + "group": "Reference", + "pages": [ + "migration-from-v1", + "changelog" + ] + } + ] + } +} diff --git a/docs-site/introduction.mdx b/docs-site/introduction.mdx new file mode 100644 index 0000000..07d65d4 --- /dev/null +++ b/docs-site/introduction.mdx @@ -0,0 +1,89 @@ +--- +title: "NanoClaw" +description: "Build a small AI team you can understand, isolate, and customize — Claude agents in per-session containers, wired to the apps you already use." +keywords: ["NanoClaw", "Claude agent", "AI team", "Docker", "self-hosted", "v2"] +--- + +NanoClaw is an AI team that runs from your own fork. You talk to it from messaging apps, the host routes each message through explicit wiring, and each session runs inside an isolated Linux container with only the workspace you chose to mount. + +It is not a generic assistant SaaS. It is small enough to read, secure by isolation, and built for bespoke workflows: channels, providers, and utilities land as skills instead of permanent product bloat. + + +**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`, `CHANGELOG.md`. + + +## Choose your path + + + + Shortest path to a working install: clone, run the installer, pair one channel, message one agent. + + + Adapt behavior, add channels/providers, split agent groups, and customize your fork without turning it into bloatware. + + + Understand the codebase, skills model, architecture, and validation flow before changing NanoClaw itself. + + + Run NanoClaw for a team or workflow: deployment, isolation, credentials, approvals, backups, and hard limits. + + + +## The model in one screen + +```text +messaging apps + → Node host process + → central routing DB + → session inbound.db + → per-session container + → session outbound.db + → host delivery + → messaging apps +``` + +The host owns identity, routing, wirings, migrations, channel adapters, and delivery. The container owns the agent run and writes only its own outbound session DB. That split keeps SQLite single-writer rules intact and makes the isolation model inspectable. + + +If you remember one distinction, make it this: **messaging groups are chats; agent groups are workspaces and identities; wirings connect them.** Sharing a messaging app does not automatically share an agent's memory, files, mounts, or credentials. + + +## What you get + +- **AI teammates, not one blob.** Each agent group has its own identity, instructions, memory, skills, mounts, provider settings, and workspace. +- **Secure by isolation.** Sessions run in containers. Agents see mounted paths, not the whole host. If data must not mix, split agent groups instead of trusting prompt text. +- **Messaging apps as front doors.** Discord, Slack, Telegram, WhatsApp, Teams, iMessage, Matrix, Google Chat, Webex, Linear, GitHub, WeChat, and email adapters install on demand from skills. +- **Skills over features.** Trunk stays lean. Channel, provider, and utility skills copy the pieces you need into your fork. +- **Bespoke, not bloatware.** NanoClaw is meant to be forked and shaped with Claude Code. The codebase is the configuration surface when configuration would become sprawl. +- **Credentials as authority.** OneCLI Agent Vault injects secrets at request time and scopes access by agent policy; raw keys do not belong in prompts or broad environment variables. + +## Docs stance + +This staged v2 portal teaches decisions and workflows. It intentionally avoids becoming a stale CLI manual. For exact flags, fields, defaults, aliases, and command lists, run local help from the checkout you installed: + +```bash +pnpm run ncl -- help +pnpm run ncl -- groups --help +pnpm run ncl -- wirings --help +``` + +Use these pages to choose boundaries: when to split agent groups, how session modes differ, where credentials live, what operators must monitor, and how to contribute without breaking the host/container contract. + +## Next pages + + + + Start with one agent, one channel, one wiring. + + + Read the host/container split and entity model. + + + Add channels, providers, skills, and fork-level behavior. + + + Separate customers, teams, credentials, mounts, and risk. + + + +Detailed channel and provider guides will land in later stages. For subsystems not covered here yet, read the source repository's `docs/` directory next to the version you are running. diff --git a/docs-site/migration-from-v1.mdx b/docs-site/migration-from-v1.mdx new file mode 100644 index 0000000..af28cc4 --- /dev/null +++ b/docs-site/migration-from-v1.mdx @@ -0,0 +1,79 @@ +--- +title: "Migrating from v1" +description: "What changed in NanoClaw v2 and how migrate-v2.sh moves an existing v1 install forward." +keywords: ["NanoClaw v2 migration", "migrate-v2.sh", "v1 to v2", "upgrade"] +--- + + +NanoClaw v2 is a ground-up rewrite with breaking changes throughout. **It cannot be merged into an existing v1 install.** A `git pull` or `git merge` will produce conflicts you should not try to resolve by hand — abort the merge and run `migrate-v2.sh` from a fresh v2 checkout instead. + + + +**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`, `CHANGELOG.md`, `CLAUDE.md`, `migrate-v2.sh`, `docs/v1-to-v2-changes.md`, `docs/migration-dev.md`. + + +## Run the migration + +From a fresh v2 checkout next to your v1 install: + +```bash +git clone https://github.com/qwibitai/nanoclaw.git nanoclaw-v2 +cd nanoclaw-v2 +bash migrate-v2.sh +``` + +`migrate-v2.sh` finds your v1 install — a sibling directory, or whatever `NANOCLAW_V1_PATH=/path/to/nanoclaw` points to — installs prerequisites (Node, pnpm, dependencies), runs the deterministic migration steps, then `exec`s into Claude Code (`/migrate-from-v1`) for the parts that need judgment. + + +Run `migrate-v2.sh` directly from a real terminal, **not from inside a Claude Code session**. The deterministic side needs interactive prompts and real shell I/O for the Node/pnpm bootstrap, Docker, OneCLI, and the container build. The script refuses to run if stdin and stdout aren't a TTY. + + +The script is idempotent — safe to re-run. `migrate-v2-reset.sh` wipes v2 state back to clean for testing. + +### What the script does + +- Merges your v1 `.env` into v2 `.env`, never overwriting existing v2 keys +- Seeds the v2 central DB from v1's `registered_groups` +- Copies group folders (v1 `CLAUDE.md` → v2 `CLAUDE.local.md`), ports container runtime config into v2's DB-backed `container_configs`, preserves session continuity, and ports active scheduled tasks +- Interactively selects and installs the channel adapters you used in v1 +- Copies channel auth state, including the Baileys keystore and LID mappings for WhatsApp +- Builds the agent container image +- Offers a service switchover so you can test v2 — your v1 install is left untouched until you choose to switch + +### What it doesn't do + +It does not flip the system service for you. Pick *"switch to v2"* at the prompt, or do it manually after testing. It also does not migrate chat history (the v1 `messages` and `chats` tables stay in the v1 checkout), `router_state`, or v1 session rows. + +### What Claude Code handles + +After the deterministic steps, `migrate-v2.sh` hands off to the `/migrate-from-v1` skill for owner seeding ("which handle is you?"), access-policy setup, `CLAUDE.local.md` cleanup, DB-backed container-config validation, and replaying any fork customizations. + +## What changed in v2 + +v1 was one Node process with one SQLite file and native channel adapters. v2 is a host that spawns per-session Docker containers, splits state across a central DB plus a per-session DB pair, routes through an explicit entity model, and installs channels as skills from a sibling branch. + +| Area | v1 | v2 | +|------|----|----| +| Process model | Single Node process; the agent ran in the same process as the router | Node host spawns a Bun-runtime Docker container per session; they communicate only through the two session DBs | +| Identity and privilege | One flat `registered_groups` table; `is_main = 1` flagged the privileged group | Explicit `users`, `user_roles` (owner, admin — global or scoped), and `agent_group_members`; privilege is user-level, not channel-level | +| Routing | A chat was wired to one folder via an opaque `trigger_pattern` regex | `agent_groups` ↔ `messaging_group_agents` ↔ `messaging_groups` many-to-many; the wiring carries `engage_mode`, `engage_pattern`, `sender_scope`, `ignored_message_policy`, `session_mode`, and `priority` | +| Storage | One SQLite file at `store/messages.db` | Three DB shapes: central `data/v2.db`, per-session `inbound.db` (host writes), per-session `outbound.db` (container writes) | +| Scheduling | A dedicated `scheduled_tasks` table | Tasks are `messages_in` rows with `kind='task'` in a session's `inbound.db` | +| Credentials | Plain `.env` environment variables passed to anything that needed them | OneCLI Agent Vault at `http://127.0.0.1:10254`; agents are scoped to specific secrets and never see raw values | +| Channels | Native adapters imported in `src/channels/` | Adapters live on the `channels` branch; `/add-` skills copy them into your fork | +| Providers | Third-party model support via `.env` overrides | `claude` baked into trunk; OpenCode, Codex, and Ollama install via `/add-opencode`, `/add-codex`, `/add-ollama-provider`, configurable per agent group | +| Group folders and runtime config | `groups//CLAUDE.md` plus filesystem config | `groups//` holds workspace/instructions; `CLAUDE.md` is composed at container spawn from a shared base, `.claude-fragments/*`, and `CLAUDE.local.md`; runtime config lives in central `container_configs` and is managed by `ncl groups config` | +| Channel isolation | Implicit | Three explicit levels — separate agent groups; a shared agent with separate sessions (`session_mode: 'shared'`); or one shared session across channels (`session_mode: 'agent-shared'`) | + +For the full vocabulary of where v1 things moved, see [`docs/v1-to-v2-changes.md`](https://github.com/qwibitai/nanoclaw/blob/main/docs/v1-to-v2-changes.md) in the source repo, and [`docs/migration-dev.md`](https://github.com/qwibitai/nanoclaw/blob/main/docs/migration-dev.md) for development notes. + +## Related + + + + The v2 entity model and message flow in detail. + + + The three-DB model and the two-DB session split. + + diff --git a/docs-site/operational-boundaries.mdx b/docs-site/operational-boundaries.mdx new file mode 100644 index 0000000..94ff0bb --- /dev/null +++ b/docs-site/operational-boundaries.mdx @@ -0,0 +1,80 @@ +--- +title: "Operational boundaries" +description: "Business and enterprise evaluation guidance for NanoClaw: isolation, credentials, approvals, backups, monitoring, and hard limits." +keywords: ["NanoClaw enterprise", "operations", "isolation", "credentials", "approvals", "governance"] +tag: "NEW" +--- + +NanoClaw can run as the AI team behind a real workflow, but its business story is not a procurement checklist. It is a set of hard boundaries you can inspect: one host process, per-session containers, explicit agent groups, scoped credentials, approvals, and SQLite state you can back up. + + +**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`, `docs/build-and-runtime.md`, `docs/db.md`, `docs/isolation-model.md`, `src/session-manager.ts`, `src/container-runner.ts`, `src/db/schema.ts`, and `src/onecli-approvals.ts`. + + +## Who this path is for + +Use this path if NanoClaw will serve a team, a customer workflow, regulated data, or a business process where data boundaries matter. If you only need a personal assistant, start with [Quickstart](/quickstart). If you are shaping behavior, read [Tinker/customize](/tinker-customize). + +## Decision map + +| Decision | Default for real work | Why | +|----------|-----------------------|-----| +| Customer or department separation | Separate agent groups | Keeps memory, files, mounts, credentials, and settings apart | +| Credential access | OneCLI Agent Vault policy | Treats credentials as authority, not configuration | +| Human approval | Approval-gated actions for authority changes and external side effects | Keeps the agent from silently expanding power | +| Persistence | Back up central DB and session folders together | Routing and conversations live in different SQLite files | +| Operations | Monitor host service, container runtime, session heartbeat mtimes, delivery failures, approvals, and storage growth | Containers are replaceable; the host data directory is not | + +## What to separate + +Create separate agent groups for: + +- customers or tenants +- departments or teams with different data access +- workflows with different credentials +- different filesystem mounts +- different model/provider/runtime policies +- anything where a leaked conversation or file would matter + +A shared session is for intentionally shared context. It is not a convenience shortcut for confidential workflows. + + +Prompt text is not an isolation boundary. If two workflows must not share files, memory, credentials, mounts, or conversation history, use separate agent groups. + + +## Credentials and approvals + +Treat credentials as authority. Put them behind OneCLI Agent Vault, scope them to the agent group that needs them, and keep raw keys out of prompts, chats, docs snippets, and broad environment variables. + +Approval-gate tools that can change authority or create external effects: sending money, placing orders, calling customers, emailing outside the team, changing credentials, installing packages, adding MCP servers, or modifying deployment config. + +## What NanoClaw does not promise + +NanoClaw gives inspectable isolation primitives. It does not replace: + +- OS hardening +- network policy +- SIEM or DLP +- compliance review +- MDM +- customer-specific audit processes +- human approval for high-risk actions + +That is a feature, not an apology. NanoClaw stays small enough to understand instead of pretending to be an enterprise governance platform. + +## Related + + + + Host service, runtime, data directory, backups, and upgrades. + + + Where state lives and why each SQLite DB has one writer. + + + Messaging groups, agent groups, wirings, and session modes. + + + The source-verified host/container model behind the boundaries. + + diff --git a/docs-site/quickstart.mdx b/docs-site/quickstart.mdx new file mode 100644 index 0000000..0c6f1c3 --- /dev/null +++ b/docs-site/quickstart.mdx @@ -0,0 +1,112 @@ +--- +title: "Quickstart" +description: "Install NanoClaw v2 and pair your first channel — from a fresh machine to a named agent you can message." +keywords: ["NanoClaw install", "quickstart", "setup", "nanoclaw.sh"] +--- + +`nanoclaw.sh` walks you from a fresh machine to a named agent you can message. It installs Node, pnpm, and Docker if they're missing, registers your Anthropic credential with OneCLI, builds the agent container, and pairs your first channel. If a step fails, Claude Code is invoked automatically to diagnose and resume from where it broke. + + +**For: everyone.** You do not need to understand every table or CLI flag to start. The first goal is one agent group, one messaging group, and one wiring between them. + + + +**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`, `nanoclaw.sh`, `package.json`, `.nvmrc`, `docs/REQUIREMENTS.md`, `CHANGELOG.md`. + + +## Requirements + +- macOS or Linux (Windows via WSL2) +- Node.js 20+ and pnpm 10+ — the installer adds both if they're missing (the repo pins Node 22 via `.nvmrc`) +- [Docker Desktop](https://www.docker.com/products/docker-desktop) (macOS/Windows) or Docker Engine (Linux) +- [Claude Code](https://claude.ai/download) — used for `/customize`, `/debug`, error recovery during setup, and every `/add-` skill +- An Anthropic account — setup registers your Anthropic credential with OneCLI's Agent Vault + +## Install + +```bash +git clone https://github.com/qwibitai/nanoclaw.git nanoclaw-v2 +cd nanoclaw-v2 +bash nanoclaw.sh +``` + + + + Run `bash nanoclaw.sh` from the cloned directory. It bootstraps Node, pnpm, and native modules under a progress spinner, then hands off to the scripted setup flow. + + + The setup flow installs Docker if missing, installs project dependencies, registers your Anthropic credential with OneCLI, and builds the `nanoclaw-agent` container image. + + + Pick a channel to connect — Telegram, Discord, WhatsApp, or a local CLI for testing. The matching `/add-` skill copies the adapter into your fork and wires it up. + + + Talk to your assistant with the trigger word (default `@Andy`). For example: `@Andy compile AI news from Hacker News and message me a briefing every weekday at 9am`. + + + +If a step fails, `nanoclaw.sh` hands control to Claude Code to diagnose and resume. If that doesn't resolve it, run `claude`, then `/debug`. + + +Already running NanoClaw v1? Don't run `nanoclaw.sh` over it and don't `git merge` v2 into your v1 checkout — see [Migrating from v1](/migration-from-v1). + + +## Run as a service + +NanoClaw runs as a single host process, managed by your platform's service manager: + + + +```bash macOS (launchd) +launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist +launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist +launchctl kickstart -k gui/$(id -u)/com.nanoclaw # restart +``` + +```bash Linux (systemd) +systemctl --user start nanoclaw +systemctl --user stop nanoclaw +systemctl --user restart nanoclaw +``` + + + +## Develop locally + +```bash +pnpm run dev # host with hot reload +pnpm run build # compile host TypeScript (src/) +pnpm run ncl -- help # inspect the admin CLI for groups, wirings, approvals, sessions, config +./container/build.sh # rebuild the agent container image (nanoclaw-agent:latest) +pnpm test # host tests (vitest) +``` + +The agent-runner is a separate Bun package under `container/agent-runner/`. It runs `bun test` for its own tests and never shares modules with the host — see [Architecture overview](/architecture) for the Node-host / Bun-container split. + +## When you need exact command help + +This portal avoids copying the full command reference because the installed CLI is the version-specific source of truth. Use docs pages for concepts and workflows; use local help for syntax, flags, defaults, and aliases: + +```bash +pnpm run ncl -- help +pnpm run ncl -- groups --help +pnpm run ncl -- wirings --help +pnpm run ncl -- sessions --help +``` + +## Next steps + + + + Add channels/providers, split agent groups, and shape your fork. + + + Understand the codebase, skills, tests, and source boundaries. + + + Isolation, credentials, approvals, backups, and hard limits for real workflows. + + + Already running NanoClaw v1? Use `migrate-v2.sh` instead. + + diff --git a/docs-site/tinker-customize.mdx b/docs-site/tinker-customize.mdx new file mode 100644 index 0000000..8855255 --- /dev/null +++ b/docs-site/tinker-customize.mdx @@ -0,0 +1,93 @@ +--- +title: "Tinker/customize" +description: "How to adapt NanoClaw behavior: channels, providers, skills, agent groups, and fork-level changes without losing the isolation model." +keywords: ["NanoClaw customization", "channels", "providers", "skills", "agent groups"] +tag: "NEW" +--- + +NanoClaw is built to be changed. The trick is to change the right layer: add a skill when you need an integration, split an agent group when you need a boundary, edit the fork when configuration would become a tiny product of its own. + + +**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/skills-as-branches.md`, `docs/isolation-model.md`, `docs/setup-wiring.md`, `docs/ollama.md`, `src/modules/self-mod/project.md`, and `container/skills/self-customize/SKILL.md`. + + +## Start with the boundary + +Before adding a channel, provider, MCP server, package, or mount, decide what must stay separate. + +| If you need... | Use... | +|----------------|--------| +| A different personality, memory, credentials, files, mounts, packages, model, or provider | A separate agent group | +| The same assistant on two chats, but independent conversations | One agent group with separate sessions | +| One conversation visible from several channels | One agent group with an agent-shared session | +| A reusable capability that should not live in trunk forever | A skill | +| Behavior that is truly yours | A fork-level code change | + + +Do not use prompt instructions as a security boundary. If two workflows must not share files, memory, credentials, mounts, or conversation history, split the agent groups. + + +## Add channels and providers with skills + +Trunk ships the registry and the core runtime. Channel adapters and alternative providers are installed from long-lived skill branches: + +- **Channels** — Discord, Slack, Telegram, WhatsApp, Teams, Linear, GitHub, iMessage, Webex, Resend, Matrix, Google Chat, and similar adapters. +- **Providers** — OpenCode, Codex, Ollama, and other non-default agent/provider integrations. +- **Utility skills** — focused tools such as voice, vision, PDFs, outbound calls, or workflow-specific scripts. + +Each `/add-` skill should be idempotent: fetch the source, copy only the module it needs, append registration imports, install pinned dependencies, and build. That keeps NanoClaw bespoke without turning trunk into a catalog of dormant integrations. + + +No channel is the default. Avoid WhatsApp-centric assumptions unless you are editing a WhatsApp-specific page or skill. + + +## Customize the fork, not a hidden product + +NanoClaw's opinionated path is direct: keep the codebase small enough that Claude Code can explain it and help you change it. + +Good customization targets: + +- channel adapter behavior +- agent-group prompts and memory +- per-group packages, mounts, MCP servers, model, and effort +- utility skills under `container/skills//` +- approval-gated tools for actions with external side effects +- small host changes that keep the routing and database invariants intact + +Bad customization targets: + +- writing to `inbound.db` from the container +- making the host and container both write the same SQLite file +- hiding credential scope in prompt text +- copying long CLI reference tables into docs +- resurrecting v1 concepts such as `data/ipc`, `manifest.yaml`, `.nanoclaw/state.yaml`, or `apply-skill.ts` + +## When you need exact commands + +This page describes the shape of the work. Use local CLI help for exact syntax, flags, defaults, aliases, and generated examples: + +```bash +pnpm run ncl -- help +pnpm run ncl -- groups --help +pnpm run ncl -- groups config --help +pnpm run ncl -- wirings --help +``` + +If a docs change needs a long command table, the better fix is usually to improve `src/cli` help metadata and point readers there. + +## Related + + + + Messaging groups, agent groups, wirings, sessions, and trigger rules. + + + The host/container contract you should preserve while customizing. + + + Codebase map, validation flow, and contribution boundaries. + + + Use runtime boundaries when the stakes are data, credentials, or customers. + +