Files
nanoclaw/CLAUDE.md
T
gavrielc 45c35a08f0 docs(v2/db): add database architecture reference
Split into three files linked from CLAUDE.md's v2 docs index:

- v2-db.md — overview: three-DB model, cross-mount rules, central-vs-session
  decision, design patterns, readers/writers map.
- v2-db-central.md — every table in data/v2.db plus migration history.
- v2-db-session.md — per-session inbound.db / outbound.db schemas, session
  folder layout, seq parity invariant, lazy schema evolution.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 10:37:26 +03:00

9.4 KiB

NanoClaw

Personal Claude assistant. See README.md for philosophy and setup. Architecture lives in docs/v2-*.md.

Quick Context (v2)

v2 is the current branch and codebase. v1 still exists under src/v1/ and container/agent-runner/src/v1/ for reference but is no longer the runtime. If a file mentions v1 in its comments, it is probably stale.

The host is a single Node process that orchestrates per-session agent containers. Platform messages land via channel adapters, route through an entity model (users → messaging groups → agent groups → sessions), get written into the session's inbound DB, and wake a container. The agent-runner inside the container polls the DB, calls Claude, and writes back to the outbound DB. The host polls the outbound DB and delivers through the same adapter.

Everything is a message. There is no IPC, no file watcher, no stdin piping between host and container. The two session DBs are the sole IO surface.

Entity Model

users (id "<channel>:<handle>", kind, display_name)
user_roles (user_id, role, agent_group_id)       — owner | admin (global or scoped)
agent_group_members (user_id, agent_group_id)    — unprivileged access gate
user_dms (user_id, channel_type, messaging_group_id) — cold-DM cache

agent_groups (workspace, memory, CLAUDE.md, personality, container config)
    ↕ many-to-many via messaging_group_agents (session_mode, trigger_rules, priority)
messaging_groups (one chat/channel on one platform; unknown_sender_policy)

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

Privilege is user-level (owner/admin), not agent-group-level. See docs/v2-isolation-model.md for the three isolation levels (agent-shared, shared, separate agents).

Two-DB Session Split

Each session has two SQLite files under data/v2-sessions/<session_id>/:

  • inbound.db — host writes, container reads. messages_in, routing, destinations, pending_questions, processing_ack.
  • outbound.db — container writes, host reads. messages_out, session_state.

Exactly one writer per file — no cross-mount lock contention. Heartbeat is a file touch at /workspace/.heartbeat, not a DB update. Host uses even seq numbers, container uses odd.

Central DB

data/v2.db holds everything that isn't per-session: users, user_roles, agent_groups, messaging_groups, wiring, pending_approvals, user_dms, chat_sdk_* (for the Chat SDK bridge), schema_version. Migrations live at src/db/migrations/.

Key Files

File Purpose
src/index.ts Entry point: init DB, 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 (schedule, approvals, etc.)
src/host-sweep.ts 60s sweep: processing_ack sync, stale detection, due-message wake, recurrence
src/session-manager.ts Resolves sessions; opens inbound.db / outbound.db; manages heartbeat path
src/container-runner.ts Spawns per-agent-group Docker containers with session DB + outbox mounts, OneCLI ensureAgent
src/container-runtime.ts Runtime selection (Docker vs Apple containers), orphan cleanup
src/access.ts pickApprover, pickApprovalDelivery, admin resolution for NANOCLAW_ADMIN_USER_IDS
src/onecli-approvals.ts OneCLI credentialed-action approval bridge
src/user-dm.ts Cold-DM resolution + user_dms cache
src/group-init.ts Per-agent-group filesystem scaffold (CLAUDE.md, skills, agent-runner-src overlay)
src/db/ DB layer — agent_groups, messaging_groups, sessions, user_roles, user_dms, pending_*, migrations
src/channels/ Channel adapters + Chat SDK bridge
container/agent-runner/src/ Agent-runner: poll loop, formatter, provider abstraction, MCP tools, destinations
container/skills/ Container skills mounted into every agent session
groups/<folder>/ Per-agent-group filesystem (CLAUDE.md, skills, per-group agent-runner-src/ overlay)
scripts/init-first-agent.ts Bootstrap the first DM-wired agent (used by /init-first-agent skill)

Self-Modification

One tier of agent self-modification today:

  1. install_packages / add_mcp_server / request_rebuild — changes to the per-agent-group container config only (apt/npm deps, wire an existing MCP server). Admin approval, rebuild, container restart. container/agent-runner/src/mcp-tools/self-mod.ts.

A second tier (direct source-level self-edits via a draft/activate flow) is planned but not yet implemented.

Secrets / Credentials / OneCLI

API keys, OAuth tokens, and auth credentials are managed by the OneCLI gateway. Secrets are injected into per-agent containers at request time — none are passed in env vars or through chat context. src/onecli-approvals.ts, ensureAgent() in container-runner.ts. Run onecli --help.

Skills

Four types of skills. See CONTRIBUTING.md for the full taxonomy.

  • Feature skillsskill/* branches merged via scripts/apply-skill.ts (e.g. /add-discord-v2, /add-slack-v2, /add-whatsapp-v2)
  • Utility skills — ship code files alongside SKILL.md (e.g. /claw)
  • Operational skills — instruction-only workflows (/setup, /debug, /customize, /init-first-agent, /manage-channels, /init-onecli, /update-nanoclaw)
  • Container skills — loaded inside agent containers at runtime (container/skills/: welcome, self-customize, agent-browser, slack-formatting)
Skill When to Use
/setup First-time install, auth, service config
/init-first-agent Bootstrap the first DM-wired agent (channel pick → identity → wire → welcome DM)
/manage-channels Wire channels to agent groups with isolation level decisions
/customize Adding channels, integrations, behavior changes
/debug Container issues, logs, troubleshooting
/update-nanoclaw Bring upstream updates into a customized install
/init-onecli Install OneCLI Agent Vault and migrate .env credentials

Contributing

Before creating a PR, adding a skill, or preparing any contribution, you MUST read CONTRIBUTING.md. It covers accepted change types, the four skill types and their guidelines, SKILL.md format rules, and the pre-submission checklist.

Development

Run commands directly — don't tell the user to run them.

pnpm run dev          # Host with hot reload
pnpm run build        # Compile host TypeScript (src/)
./container/build.sh  # Rebuild agent container image (nanoclaw-agent:latest)
pnpm test             # Host tests

Container typecheck is a separate tsconfig — if you edit container/agent-runner/src/, run pnpm exec tsc -p container/agent-runner/tsconfig.json --noEmit to check it.

Service management:

# 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

# Linux (systemd)
systemctl --user start|stop|restart nanoclaw

Host logs: logs/nanoclaw.log (normal) and logs/nanoclaw.error.log (errors only — some delivery/approval failures only show up here).

Supply Chain Security (pnpm)

This project uses pnpm with minimumReleaseAge: 4320 (3 days) in pnpm-workspace.yaml. New package versions must exist on the npm registry for 3 days before pnpm will resolve them.

Rules — do not bypass without explicit human approval:

  • minimumReleaseAgeExclude: Never add entries without human sign-off. If a package must bypass the release age gate, the human must approve and the entry must pin the exact version being excluded (e.g. package@1.2.3), never a range.
  • onlyBuiltDependencies: Never add packages to this list without human approval — build scripts execute arbitrary code during install.
  • pnpm install --frozen-lockfile should be used in CI, automation, and container builds. Never run bare pnpm install in those contexts.

v2 Docs Index

Doc Purpose
docs/v2-architecture-draft.md Full architecture writeup
docs/v2-api-details.md Host API + DB schema details
docs/v2-db.md DB architecture overview: three-DB model, cross-mount rules, readers/writers map
docs/v2-db-central.md Central DB (data/v2.db) — every table + migration system
docs/v2-db-session.md Per-session inbound.db + outbound.db schemas + seq parity
docs/v2-agent-runner-details.md Agent-runner internals + MCP tool interface
docs/v2-isolation-model.md Three-level channel isolation model
docs/v2-setup-wiring.md What's wired, what's open in the setup flow
docs/v2-checklist.md Rolling status checklist across all subsystems
docs/v2-architecture-diagram.md Diagram version of the architecture

Container Build Cache

The container buildkit caches the build context aggressively. --no-cache alone does NOT invalidate COPY steps — the builder's volume retains stale files. To force a truly clean rebuild, prune the builder then re-run ./container/build.sh.