What is a group?
A group is:- A group chat or individual conversation on any channel (identified by
jid) - A dedicated folder under
groups/{name}/ - An isolated Claude conversation session
- A set of permissions and mount configurations
- A separate IPC namespace for container communication
Groups are the fundamental isolation boundary in NanoClaw. Each group operates independently with its own context and history.
Group types
Main group (admin)
The main group is special:- Typically a self-chat or DM with the bot on your primary platform
- Has full administrative privileges
- Can manage other groups
- Can schedule tasks for any group
- Has read-write access to project root (read-only mount)
- Folder is always
main
Non-main groups
All other groups:- One per group chat or conversation across any connected channel
- Limited to their own context and operations
- Cannot access other groups’ data
- Cannot send messages to other chats
- Require trigger pattern (
@{ASSISTANT_NAME}) unless disabled
Group registration
Groups must be registered before the agent will respond to messages.Registration process
- Main group sends command to register a new group
- Agent calls
register_groupvia IPC - Host validates folder name and creates directory structure
- Group added to SQLite database
- Group folder and logs directory created
Registration data structure
Folder naming rules
- Must be alphanumeric with dashes/underscores only
- Cannot contain
..or/ - Main group always uses
main - Typically derived from group name (e.g., “Family Chat” →
family-chat)
Group isolation mechanisms
1. Filesystem isolation
Each group has a dedicated directory structure:groups
{group-folder}
CLAUDE.md
logs
| Path | Main Group | Non-Main Group |
|---|---|---|
| Own group folder | Read-write | Read-write |
| Project root | Read-only | Not mounted |
Global memory (groups/global/) | Via project mount | Read-only mount (if exists) |
| Other groups’ folders | Via project root (ro) | Not accessible |
| Additional mounts | Configurable | Read-only unless allowed |
Main group can technically access other groups’ folders via the project root mount, but non-main groups cannot access anything outside their own folder.
2. Session isolation
Each group maintains a separate Claude conversation session:data/sessions
{group-folder}
.claude
settings.json
skills
agent-runner-src
- Groups cannot see other groups’ conversation history
- Groups cannot access files read by other groups
- Groups cannot see other groups’ user preferences (memory)
- Each group starts with fresh session on first invocation
3. IPC namespace isolation
Each group has its own IPC directory:data/ipc
{group-folder}
messages
tasks
input
current_tasks.json
available_groups.json
- Groups from sending messages on behalf of other groups
- Groups from scheduling tasks for other groups
- Groups from seeing other groups’ task lists
- Cross-group privilege escalation via IPC
4. Message cursor isolation
Each group has its own message processing cursor:- Messages to one group don’t affect others
- Each group processes messages independently
- Crash recovery works per-group (no cross-contamination)
- Groups can have different processing states
Global memory
The global memory directory (groups/global/) is special:
- Writable only by main group
- Read-only for all other groups
- Contains shared knowledge and context
- Typically includes a
CLAUDE.mdfile loaded by all agents
- Shared instructions for all agents
- Common reference information
- Cross-group context (user preferences, facts)
- Coordination data between groups
How global memory is loaded
How global memory is loaded
Claude Agent SDK automatically loads
CLAUDE.md files from all mounted directories when CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 is set.Mount structure:/workspace/group/CLAUDE.md(per-group, read-write)/workspace/global/CLAUDE.md(global, read-only for non-main)/workspace/project/CLAUDE.md(project context, main only)
Group queue and concurrency
The GroupQueue manages per-group execution:- Max concurrent containers: 5 by default (
MAX_CONCURRENT_CONTAINERS) - Per-group queueing: Each group has independent message and task queues
- Priority: Tasks before messages (tasks won’t be re-discovered from DB)
- Idle containers: Kept alive for 30 minutes to handle follow-ups
- Message piping: Follow-up messages sent to active containers via IPC
When a group’s container is already active, new messages are piped directly to the running container instead of spawning a new one. This preserves conversation flow.
Trigger pattern
Non-main groups require a trigger pattern to activate:- Default pattern:
@{ASSISTANT_NAME}(case insensitive) - Configured via:
ASSISTANT_NAMEenvironment variable - Example:
@AndyifASSISTANT_NAME=Andy - Can be disabled: Set
requiresTrigger: falsein group config
- Prevents agent from responding to every message in group chats
- Allows selective activation (“@Andy what’s the weather?”)
- Reduces noise in active group conversations
- Main group doesn’t need trigger (private self-chat)
- Stored in database
- Included as context when trigger eventually arrives
- Not processed immediately
- Accumulate between triggered responses
Triggers check both message content and sender authorization. A message must match the trigger pattern and the sender must be allowed by the sender allowlist (specifically,
isTriggerAllowed checks against the allowlist configuration). Messages from the bot itself (is_from_me) always pass the sender check.Additional mounts
Groups can have extra directories mounted viacontainerConfig.additionalMounts:
The
containerPath must be relative (no leading /). It is automatically prefixed with /workspace/extra/, so "website" becomes /workspace/extra/website inside the container.- Checked against mount allowlist (
~/.config/nanoclaw/mount-allowlist.json) - Symlinks resolved before validation
- Blocked patterns rejected (
.ssh,.env, etc.) nonMainReadOnlysetting enforced for non-main groups
Group lifecycle
Creation
- Main group sends registration command
- Folder created under
groups/{folder}/ - Session directory created under
data/sessions/{folder}/ - IPC directory created under
data/ipc/{folder}/ - Skills synced to
.claude/skills/ - Agent runner source copied to
agent-runner-src/ - Group added to database
Active operation
- Messages arrive via a connected channel (WhatsApp, Telegram, Discord, etc.)
- Stored in database with chat JID
- Router checks for trigger (if required)
- GroupQueue spawns container or pipes to active one
- Container mounts group folder and session
- Agent processes messages and generates response
- Response routed back via the originating channel
Deactivation
- No explicit deactivation needed
- Groups remain registered until explicitly removed
- Inactive groups simply don’t receive messages
- Sessions and folders persist across restarts
Removal
- Must be done manually (no built-in unregister)
- Delete group from database:
DELETE FROM registered_groups WHERE folder = '{folder}' - Optionally delete folders:
groups/{folder}/,data/sessions/{folder}/,data/ipc/{folder}/
Best practices
- Use descriptive folder names:
project-xinstead ofgroup1 - Set requiresTrigger: false carefully: Only for private contexts
- Limit additional mounts: Only mount what’s necessary
- Use global memory for shared context: Avoid duplicating common knowledge
- Monitor group logs: Check
groups/{folder}/logs/for issues - Keep main group secure: It has full access to everything