From b6386fb6e9cd84de2221a37cdac2ce5261e85383 Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Sat, 9 May 2026 17:37:56 +0000 Subject: [PATCH] Sync docs for v2.0.48: container config DB, restart, CLI scope Generated-By: mintlify-agent --- advanced/container-runtime.mdx | 27 ++++++++++++++++++++++++--- api/configuration.mdx | 31 ++++++++++++++++++++++++++++++- api/group-management.mdx | 2 +- changelog/docs-updates.mdx | 12 ++++++++++++ changelog/index.mdx | 11 +++++++++++ concepts/containers.mdx | 32 +++++++++++++++++++++++++------- concepts/groups.mdx | 4 ++-- 7 files changed, 105 insertions(+), 14 deletions(-) diff --git a/advanced/container-runtime.mdx b/advanced/container-runtime.mdx index 045e018..3dc67ca 100644 --- a/advanced/container-runtime.mdx +++ b/advanced/container-runtime.mdx @@ -77,7 +77,7 @@ The agent container is built from `container/Dockerfile` and includes: ### Per-agent-group images -Agent groups can specify custom packages in `container.json`. The host builds a derived Docker image: +Agent groups can specify custom packages via their container config (managed with `ncl groups config add-package/remove-package`). The host builds a derived Docker image: - Tag: derived from the checkout-scoped base image and agent group - Built on top of `nanoclaw-agent-v2-:latest` @@ -121,7 +121,7 @@ Containers are spawned by the `spawnContainer` function. Wake calls are deduplic - The host reads `container.json` and resolves provider contributions. + The host reads the `container_configs` row for the agent group, materializes it to `groups//container.json`, and resolves provider contributions. @@ -151,7 +151,7 @@ Containers are spawned by the `spawnContainer` function. Wake calls are deduplic |------|---------------|------|---------| | Session folder | `/workspace` | RW | inbound.db, outbound.db, outbox/, inbox/ | | Agent group folder | `/workspace/agent` | RW | Working files | -| container.json | `/workspace/agent/container.json` | RO | Nested read-only config | +| container.json | `/workspace/agent/container.json` | RO | Materialized from the `container_configs` table at spawn time | | Composed CLAUDE.md | `/workspace/agent/CLAUDE.md` | RO | Regenerated each spawn | | Global memory | `/workspace/global` | RO | Shared instructions | | Agent-runner source | `/app/src` | RO | Bind mount from host | @@ -170,8 +170,29 @@ Containers have two timeout/detection mechanisms: ### Container shutdown - `killContainer(sessionId, reason)` stops the container via `docker stop`, falls back to SIGKILL +- An optional `onExit` callback fires after the process exits, guaranteeing the old container is gone before any respawn happens - On close/error, the session is marked stopped and typing indicators are cleared +### Explicit restart with on-wake messages + +Config CLI operations no longer auto-kill containers. To restart an agent group's container, use: + +```bash +ncl groups restart --id [--rebuild] [--message ] +``` + +When `--message` is provided, the host writes the wake message to `messages_in` with the `on_wake` flag set, kills the running container, and respawns via the `onExit` callback. The `on_wake` flag ensures the message is picked up only by the fresh container's first poll iteration — a dying container in its SIGTERM grace period can never steal it. + +Self-mod approval handlers (`install_packages`, `add_mcp_server`) use the same race-free mechanism: rebuild the image when needed, write an `on_wake` message, kill the container, and respawn via `onExit`. + +### CLI scope enforcement + +The agent group's `cli_scope` setting (`disabled`, `group`, `global`) controls what the in-container agent can do via `ncl`. Enforcement is host-side, applied in the dispatcher: + +- `disabled` rejects every `cli_request` and excludes the `ncl` instructions from the composed CLAUDE.md +- `group` (default) restricts requests to `groups`, `sessions`, `destinations`, and `members` for the agent group itself, auto-fills `--id` and group args, rejects cross-group access, blocks `cli_scope` mutations, and runs post-handler result filtering to prevent cross-group data leaks in list responses +- `global` (set automatically for owner agent groups) is unrestricted + ## Credential injection The OneCLI SDK's `applyContainerConfig()` configures each container's network to route through the vault: diff --git a/api/configuration.mdx b/api/configuration.mdx index 782d8de..07aa4fb 100644 --- a/api/configuration.mdx +++ b/api/configuration.mdx @@ -4,7 +4,7 @@ description: Environment variables and configuration options for NanoClaw contai tag: "UPDATED" --- -NanoClaw configuration is managed through environment variables, the `.env` file, and the `src/config.ts` module. In v2, some configuration has moved to `container.json` per agent group. +NanoClaw configuration is managed through environment variables, the `.env` file, and the `src/config.ts` module. In v2, per-agent-group container runtime config (provider, model, packages, MCP servers, mounts, skills, `cli_scope`) lives in the `container_configs` table in the central DB. The host materializes it to `groups//container.json` at spawn time. Manage with `ncl groups config get/update`. ## Environment variables @@ -93,6 +93,35 @@ All paths are absolute and resolved from the project root: `~/.config/nanoclaw/mount-allowlist.json` — mount security allowlist (never mounted into containers) +## Per-agent-group container config + +Stored in the `container_configs` table in the central DB; one row per agent group. Materialized to `groups//container.json` at spawn time. Edit only via `ncl` — do not modify `container.json` directly. + +Common fields: + +| Field | Description | +|-------|-------------| +| `provider`, `model` | Agent provider and model selection | +| `packages.apt`, `packages.npm` | Extra apt and npm packages to bake into the per-group image | +| `mcp_servers` | Additional MCP servers wired to the container | +| `additional_mounts` | Extra host directories (validated against the mount allowlist) | +| `skills` | Container skill list | +| `cli_scope` | `disabled` / `group` (default) / `global` — controls in-container `ncl` access | + +Manage container config: + +```bash +ncl groups config get --id +ncl groups config update --id --model +ncl groups config add-mcp-server --id ... +ncl groups config remove-mcp-server --id ... +ncl groups config add-package --id --type apt --name +ncl groups config remove-package --id --type npm --name +ncl groups restart --id [--rebuild] [--message ] +``` + +Existing filesystem `container.json` files are backfilled into the DB automatically on first startup after upgrading. + ## Trigger pattern The default trigger pattern is generated from `ASSISTANT_NAME`: diff --git a/api/group-management.mdx b/api/group-management.mdx index 0bfaa96..0b8fadf 100644 --- a/api/group-management.mdx +++ b/api/group-management.mdx @@ -23,7 +23,7 @@ interface AgentGroup { ``` - Each agent group has a folder under `groups/{folder}/` -- Container configuration lives on disk (`container.json`), not in the database +- Container configuration lives in the `container_configs` table in the central DB; the host materializes it to `groups//container.json` at spawn time. Manage with `ncl groups config get/update`. - Each gets its own OneCLI agent identifier for credential scoping ### Messaging groups diff --git a/changelog/docs-updates.mdx b/changelog/docs-updates.mdx index 3da553f..31b1eba 100644 --- a/changelog/docs-updates.mdx +++ b/changelog/docs-updates.mdx @@ -5,6 +5,18 @@ icon: "file-pen" rss: true --- + + Documented the v2.0.45 → v2.0.48 changes: per-agent-group container runtime config moved from `groups//container.json` files to the `container_configs` central-DB table (filesystem configs backfilled on startup, materialized to `container.json` at spawn time), explicit container restart via `ncl groups restart` with race-free `on_wake` messages, and per-group `cli_scope` (`disabled` / `group` / `global`). + + ## Updated + - **`concepts/containers.mdx`**: container config table sourced from the DB; new "Explicit restart" subsection covering `ncl groups restart`, the `on_wake` flag, and the `onExit` callback contract; new "CLI scope" subsection. + - **`concepts/groups.mdx`**: agent group definition now references `container_configs`; additional-mounts wording aligned with DB-stored config. + - **`advanced/container-runtime.mdx`**: spawn flow reads from `container_configs` and materializes `container.json`; mounts table updated; added "Explicit restart with on-wake messages" and "CLI scope enforcement" subsections. + - **`api/configuration.mdx`**: new "Per-agent-group container config" section listing common fields and `ncl groups config` verbs, including `cli_scope`. + - **`api/group-management.mdx`**: corrected the claim that container config lives on disk only — now in the DB, materialized at spawn time. + - **`changelog/index.mdx`**: added `v2.0.48` and `v2.0.45` release entries. + + Phase A of the v2 documentation sprint — bringing the pages every new user lands on into alignment with the v2 rewrite. All claims verified directly against upstream source (`src/db/schema.ts`, `src/types.ts`, `src/config.ts`, `container/Dockerfile`, `src/delivery.ts`) rather than upstream `docs/` (which includes a stale `architecture.md` draft and a `db-session.md` that omits the `container_state` table). diff --git a/changelog/index.mdx b/changelog/index.mdx index 0608705..55ef333 100644 --- a/changelog/index.mdx +++ b/changelog/index.mdx @@ -6,6 +6,17 @@ rss: true tag: "UPDATED" --- + + - **Container config moved to DB.** Per-agent-group container runtime config (provider, model, packages, MCP servers, mounts, skills) now lives in the `container_configs` table instead of `groups//container.json`. Existing filesystem configs are backfilled automatically on startup. Managed via `ncl groups config get/update` and `config add-mcp-server/remove-mcp-server/add-package/remove-package`. + - **Explicit restart with on-wake messages.** Config CLI operations no longer auto-kill containers. New `ncl groups restart` command with `--rebuild` and `--message` flags. On-wake messages (`on_wake` column on `messages_in`) are only picked up by a fresh container's first poll, preventing dying containers from stealing them during the SIGTERM grace period. Self-mod approval handlers (`install_packages`, `add_mcp_server`) use the same race-free mechanism. + - **Per-group CLI scope.** New `cli_scope` setting on container config (`disabled` / `group` / `global`, default `group`). Controls what the agent can access via `ncl` from inside the container. `disabled` excludes CLI instructions from CLAUDE.md and blocks all requests. `group` (default) restricts to own-group resources with auto-filled args. `global` gives unrestricted access (set automatically for owner agent groups). Includes post-handler result filtering to prevent cross-group data leaks and blocks `cli_scope` escalation from group-scoped agents. + + + + - **Admin CLI (`ncl`).** New `ncl` command for querying and modifying the central DB — agent groups, messaging groups, wirings, users, roles, members, destinations, sessions, approvals, and dropped messages. Host-side transport via Unix socket; container-side transport via session DB. Write operations from inside containers go through the approval flow. `list` supports column filtering and `--limit`. Run `ncl help` for usage. + - **v1 → v2 migration.** Run `bash migrate-v2.sh` from the v2 checkout. Finds your v1 install (sibling directory or `NANOCLAW_V1_PATH`), merges `.env`, seeds the v2 DB from `registered_groups`, copies group folders (`CLAUDE.md` → `CLAUDE.local.md`), copies session data with conversation continuity, ports scheduled tasks, interactively selects and installs channels, copies container skills, builds the agent container, and offers a service switchover to test. Hands off to Claude (`/migrate-from-v1`) for owner seeding, access policy, CLAUDE.md cleanup, and fork customization porting. + + - Ground-up architectural rewrite with new entity model (users, roles, messaging groups, agent groups, wirings) - Two-database session model — `inbound.db` (host writes) and `outbound.db` (container writes) eliminate cross-mount SQLite contention diff --git a/concepts/containers.mdx b/concepts/containers.mdx index c328ee0..bbb1a7f 100644 --- a/concepts/containers.mdx +++ b/concepts/containers.mdx @@ -74,7 +74,7 @@ Containers only see what's explicitly mounted. The v2 mount structure is differe |-------|---------------|------|---------| | Session folder | `/workspace` | Read-write | `inbound.db`, `outbound.db`, `outbox/`, `.claude/` | | Agent group folder | `/workspace/agent` | Read-write | Working files, `CLAUDE.local.md` | -| Container config | `/workspace/agent/container.json` | Read-only | Nested RO mount (agent can't modify config) | +| Container config | `/workspace/agent/container.json` | Read-only | Materialized from the `container_configs` DB table at spawn time | | Composed CLAUDE.md | `/workspace/agent/CLAUDE.md` | Read-only | Regenerated each spawn | | CLAUDE.md fragments | `/workspace/agent/.claude-fragments` | Read-only | Fragment files for composition | | Global memory | `/workspace/global` | Read-only | `groups/global/` directory | @@ -82,11 +82,11 @@ Containers only see what's explicitly mounted. The v2 mount structure is differe | Agent-runner source | `/app/src` | Read-only | Shared source (bind mount from host) | | Container skills | `/app/skills` | Read-only | Shared skill definitions | | Claude SDK state | `/home/node/.claude` | Read-write | SDK state + skill symlinks | -| Additional mounts | `/workspace/extra/{name}` | Per-config | From `container.json` (validated against allowlist) | +| Additional mounts | `/workspace/extra/{name}` | Per-config | From container config (validated against allowlist) | - -The `container.json` file is mounted read-only as a nested mount inside the read-write agent group folder. This prevents the agent from modifying its own container configuration. - + +**Container config in the DB (v2.0.48+).** Per-agent-group container runtime config (provider, model, packages, MCP servers, mounts, skills, `cli_scope`) lives in the `container_configs` table in the central DB. The host materializes it to `groups//container.json` at spawn time so the container runner can read it, and mounts that file read-only into the container. Existing filesystem configs are backfilled into the DB automatically on startup. Manage with `ncl groups config get/update`. + ### Mount security @@ -143,13 +143,19 @@ Container spawning is deduplicated — concurrent wake calls for the same sessio - **Stale detection**: host sweep detects containers with old heartbeats or stuck processing_ack - **Fallback**: SIGKILL if graceful stop fails +### Explicit restart + +Config changes do not auto-kill containers. Use `ncl groups restart --id ` (with optional `--rebuild` to rebuild the image, or `--message ` to deliver a wake message after the new container starts). The host writes the on-wake message to `messages_in` with the `on_wake` flag set, kills the running container, and respawns via an `onExit` callback so the old container is fully gone before the new one starts. + +The `on_wake` flag ensures wake messages are picked up only by a fresh container's first poll iteration. This prevents the race where a dying container in its SIGTERM grace period could steal the message. Self-mod approval handlers (`install_packages`, `add_mcp_server`) use the same race-free mechanism. + Even if the container crashes, all data in session databases and mounted directories persists. Only the container process itself is ephemeral. ## Per-agent-group images -Agent groups can specify custom packages in `container.json`. The host builds a derived Docker image with additional apt and npm packages: +Agent groups can specify custom packages in their container config (use `ncl groups config add-package/remove-package`). The host builds a derived Docker image with additional apt and npm packages: - Image tag: derived from the checkout-scoped base image and agent group - Built on top of the base `nanoclaw-agent-v2-:latest` image @@ -187,7 +193,19 @@ The `nanoclaw` MCP server provides tools for container-to-host communication via - `schedule_task`, `cancel_task`, `pause_task`, `resume_task`, `update_task` — task management - `list_tasks` — view scheduled tasks -Additional MCP servers can be configured in `container.json`. +Additional MCP servers can be configured per agent group via `ncl groups config add-mcp-server/remove-mcp-server`. + +### CLI scope + +Each agent group's container config has a `cli_scope` setting that controls what the agent can do with `ncl` from inside the container: + +| Value | Behavior | +|-------|----------| +| `disabled` | Agent never sees `ncl` instructions in CLAUDE.md, and the host rejects every `cli_request` from the container. | +| `group` (default) | Agent can access `groups`, `sessions`, `destinations`, `members` only, scoped to its own agent group. `--id` and group args are auto-filled, cross-group access is rejected, and `cli_scope` changes are blocked. Post-handler result filtering prevents cross-group data leaks. | +| `global` | Unrestricted. Set automatically for owner agent groups. | + +This setting is only modifiable from outside the container (host-side `ncl` over the Unix socket) — group-scoped agents cannot escalate themselves. ### Global memory injection diff --git a/concepts/groups.mdx b/concepts/groups.mdx index 381153b..e552693 100644 --- a/concepts/groups.mdx +++ b/concepts/groups.mdx @@ -14,7 +14,7 @@ An agent group is: - A workspace with its own folder under `groups/{name}/` - An optional provider configuration -- A container configuration (`container.json`) with custom packages and mounts +- A container configuration in the `container_configs` table — provider, model, packages, MCP servers, mounts, skills, and `cli_scope`. The host materializes it to `groups//container.json` at spawn time. Manage via `ncl groups config get/update`. - The unit of credential scoping (each gets its own OneCLI agent) ### Messaging groups @@ -137,7 +137,7 @@ The global memory directory (`groups/global/`) provides shared context: ## Additional mounts -Agent groups can have extra directories mounted via `container.json`: +Agent groups can have extra directories mounted via the container config (stored in the `container_configs` table, materialized to `container.json` at spawn time): ```json {