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.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.
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, orpublic - Can be denied (sets
denied_atto 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:| Axis | Options | Purpose |
|---|---|---|
engage_mode | pattern, mention, mention-sticky | When the agent responds |
engage_pattern | Regex (e.g., '.' = always) | Pattern to match against messages |
sender_scope | all, known | Who can trigger the agent |
ignored_message_policy | drop, accumulate | What happens to non-triggering messages |
session_mode—shared(one per messaging group),per-thread(one per thread), oragent-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 theengage_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’ssession_mode:
| Mode | Behavior |
|---|---|
shared | One session per messaging group (ignores thread) |
per-thread | One session per (messaging group, thread) pair |
agent-shared | One session per agent group (all messaging groups share it) |
Session directory structure
Two-database invariants
Three critical invariants ensure correctness across Docker mount boundaries:journal_mode=DELETE— WAL’s mmapped-shmfile doesn’t refresh host-to-guest- Host opens-writes-closes per operation — closing invalidates the container’s page cache
- 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
| Role | Scope | Capabilities |
|---|---|---|
| Owner | Always global | Full system access, approves channels and senders |
| Admin | Global or per-agent-group | Approves senders within scope |
| Member | Per-agent-group | Can 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:- Owner receives an approval card
- Approve — creates a wiring with defaults (
mention-stickyfor groups,pattern='.'for DMs), admits the triggering sender, replays the original event - Deny — sets
denied_aton the messaging group; future mentions drop silently
Global memory
The global memory directory (groups/global/) provides shared context:
- Contains
CLAUDE.mdloaded 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 viacontainer.json:
- 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
/workspace/extra/{name} inside the container and are auto-discovered as additionalDirectories by the SDK.
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
- Use descriptive agent group names:
project-xinstead ofgroup1 - Choose engage mode carefully:
mentionfor noisy groups,patternfor private contexts - Limit additional mounts: only mount what’s necessary
- Use global memory for shared context: avoid duplicating common knowledge
- Set
sender_scope=knownfor sensitive groups: restricts to authorized users