Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.nanoclaw.dev/llms.txt

Use this file to discover all available pages before exploring further.

In v2, NanoClaw uses a new entity model that separates agent groups (workspaces where agents run) from messaging groups (platform chats and channels). These are connected through wirings — many-to-many relationships that control how messages are routed to agents.

Entity model

Agent groups

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
  • The unit of credential scoping (each gets its own OneCLI agent)

Messaging groups

A messaging group is:
  • A platform chat or channel identified by (channel_type, platform_id)
  • Has an unknown_sender_policy: strict, request_approval, or public
  • Can be denied (sets denied_at to silently drop future mentions)
  • Auto-created on first mention or DM

Wirings (messaging_group_agents)

Wirings connect messaging groups to agent groups with four orthogonal axes:
AxisOptionsPurpose
engage_modepattern, mention, mention-stickyWhen the agent responds
engage_patternRegex (e.g., '.' = always)Pattern to match against messages
sender_scopeall, knownWho can trigger the agent
ignored_message_policydrop, accumulateWhat happens to non-triggering messages
Additional wiring properties:
  • session_modeshared (one per messaging group), per-thread (one per thread), or agent-shared (one per agent group)
  • priority — controls evaluation order when multiple agents are wired
The many-to-many model allows a single messaging group to be wired to multiple agent groups, and a single agent group to serve multiple messaging groups.

Engage modes

Pattern mode

The agent responds whenever a message matches the engage_pattern regex. Use '.' to match all messages (equivalent to the old “no trigger required”).

Mention mode

The agent only responds when explicitly mentioned at the platform level (e.g., @bot in Discord, reply in WhatsApp).

Mention-sticky mode

The agent responds to an explicit mention OR if there’s an existing active session for this combination of agent, messaging group, and thread. Once activated by a mention, the agent continues responding in that conversation.
In mention-sticky mode, the adapter’s subscribe() method is called for platform-side bookkeeping (e.g., subscribing to a Discord thread). This is fire-and-forget.

Session management

Session resolution

Sessions are resolved based on the wiring’s session_mode:
ModeBehavior
sharedOne session per messaging group (ignores thread)
per-threadOne session per (messaging group, thread) pair
agent-sharedOne session per agent group (all messaging groups share it)

Session directory structure

data/v2-sessions/{agent_group_id}/{session_id}/
├── inbound.db      # Host writes, container reads
├── outbound.db     # Container writes, host reads
├── outbox/         # File attachments for outbound messages
├── inbox/          # File attachments from inbound messages
├── .heartbeat      # Container liveness indicator
└── .claude/        # SDK state

Two-database invariants

Three critical invariants ensure correctness across Docker mount boundaries:
  1. journal_mode=DELETE — WAL’s mmapped -shm file doesn’t refresh host-to-guest
  2. Host opens-writes-closes per operation — closing invalidates the container’s page cache
  3. One writer per file — DELETE-mode journal unlink isn’t atomic across the mount

Users and roles

User model

Users are identified by namespaced platform identifiers:
  • phone:+15551234567 (WhatsApp, iMessage)
  • tg:123456789 (Telegram)
  • discord:123456789 (Discord)
  • email:user@example.com (Gmail)

Role hierarchy

RoleScopeCapabilities
OwnerAlways globalFull system access, approves channels and senders
AdminGlobal or per-agent-groupApproves senders within scope
MemberPer-agent-groupCan interact with agents in their assigned group
The owner is the system administrator. There is always exactly one owner. Admins can be scoped to a specific agent group or have global access.

Channel approval

When a message arrives on an unwired channel (no agent wirings exist), the channel-request gate escalates to the owner:
  1. Owner receives an approval card
  2. Approve — creates a wiring with defaults (mention-sticky for groups, pattern='.' for DMs), admits the triggering sender, replays the original event
  3. Deny — sets denied_at on the messaging group; future mentions drop silently

Global memory

The global memory directory (groups/global/) provides shared context:
  • Contains CLAUDE.md loaded by all non-main agent groups
  • Injected into the system prompt via systemPrompt.append
  • Read-only for all agents

Additional mounts

Agent groups can have extra directories mounted via container.json:
{
  "additionalMounts": [
    {
      "hostPath": "/Users/you/projects/website",
      "containerPath": "website",
      "readonly": true
    }
  ]
}
Security validation:
  • Checked against mount allowlist (~/.config/nanoclaw/mount-allowlist.json)
  • Symlinks resolved before validation
  • Blocked patterns rejected
  • RW requires both mount config AND allowed root to permit it
Validated mounts appear at /workspace/extra/{name} inside the container and are auto-discovered as additionalDirectories by the SDK.
Additional mounts bypass group isolation. Only mount directories that are safe for the agent to access.

Concurrency

Container concurrency is managed globally:
  • Max concurrent containers: 5 by default (MAX_CONCURRENT_CONTAINERS)
  • Wake deduplication: concurrent wake calls for the same session share a single in-flight promise
  • Delivery polls: active poll (1s) for running containers, sweep poll (60s) for all sessions

Best practices

  1. Use descriptive agent group names: project-x instead of group1
  2. Choose engage mode carefully: mention for noisy groups, pattern for private contexts
  3. Limit additional mounts: only mount what’s necessary
  4. Use global memory for shared context: avoid duplicating common knowledge
  5. Set sender_scope=known for sensitive groups: restricts to authorized users
Last modified on April 22, 2026