Overview
NanoClaw processes messages through a polling-based architecture that connects messaging channels to isolated Claude agent containers. Each group has its own message queue, session state, and isolated filesystem.Message flow
Trigger patterns
Trigger patterns determine when the agent should respond. The default trigger is@{ASSISTANT_NAME} at the start of a message.
Usage examples
The main channel (your self-chat) doesn’t require a trigger - every message is processed automatically.
Message formatting
Messages are formatted as XML before being sent to the agent, preserving sender information and timestamps:Example formatted output
Internal tags
Agents can use<internal>...</internal> tags for reasoning that won’t be sent to users:
Agent output example
Group message queues
NanoClaw uses a per-group queue system with global concurrency limits to prevent resource exhaustion:How it works
- Each group gets its own message queue
- Multiple groups can have active containers simultaneously (up to
MAX_CONCURRENT_CONTAINERS) - When a container is idle, new messages are sent via IPC files without spawning a new container
- Idle timeout: 30 minutes by default (configurable via
IDLE_TIMEOUT)
Advanced: Message piping to active containers
Advanced: Message piping to active containers
When an agent container is already running and idle, NanoClaw writes follow-up messages as JSON files to the group’s IPC input directory instead of spawning a new container:This optimization reduces latency and container churn for active conversations.
Channel routing
NanoClaw supports multiple messaging channels through a unifiedChannel interface:
Supported channels
- WhatsApp (via
/add-whatsappskill) - Telegram (via
/add-telegramskill) - Discord (via
/add-discordskill) - Slack (via
/add-slackskill) - Gmail (via
/add-gmailskill)
Message persistence
All messages are stored in SQLite (store/messages.db) with full history:
Message retrieval
Both
getNewMessages and getMessagesSince cap results at 200 messages by default. The agent only sees the most recent 200 messages per invocation — older messages remain in the database but are not included in the agent’s prompt. This prevents unbounded result sets and out-of-memory crashes in active groups.Configuration
Polling interval
Trigger customization
To change the trigger word, ask Claude Code to modify it:ASSISTANT_NAME in src/config.ts and .env.
Group registration
Groups must be registered before the agent can respond. The main channel can register groups via IPC:Example
From the main channel:Session commands
Session commands are slash commands sent as messages that the host process intercepts before the agent sees them. They control the agent session itself rather than asking the agent to do something./compact
The/compact command triggers manual context compaction to fight “context rot” in long-running sessions. When an agent has been active for a while, its context window fills up with old messages that may no longer be relevant.
How to use it:
- The full session transcript is archived (non-destructive — nothing is lost)
- Claude Agent SDK’s built-in
/compactcommand runs, summarizing the conversation context - The session continues with a condensed context, freeing space for new messages
| Sender | Allowed? |
|---|---|
| Main group (any sender) | Yes |
Admin/trusted sender (is_from_me) in any group | Yes |
| Other senders in non-main groups | No — receives “Session commands require admin access” |
The
/compact command is installed via the skill/compact branch. It’s not available on main by default. Apply it with:src/session-commands.ts, which extracts commands from messages, validates authorization, and coordinates with the container runner.
Related documentation
- Scheduled tasks - Automate recurring agent tasks
- Agent Swarms - Multi-agent collaboration
- Customization - Modify trigger patterns and behavior