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.

NanoClaw doesn’t rely on large configuration files. Instead, customizations fall into four lanes:
  1. Code changes — for behavior baked into the orchestrator (trigger pattern, polling, timeouts)
  2. Wiring settings — per-messaging-group config stored in the central DB (engage mode, sender scope, session mode)
  3. Skills — for features and integrations (install via /add-<name>, uninstall via git revert)
  4. Mount allowlist — for which host directories an agent can see

Philosophy

From the README:
NanoClaw doesn’t use configuration files. To make changes, just tell Claude Code what you want… The codebase is small enough that Claude can safely modify it.
The result: your fork does exactly what you asked for, and nothing else. No generic system to learn — just the code you want, readable by you and by Claude Code.

Change the trigger word

The default is @Andy, derived from ASSISTANT_NAME in src/config.ts:
// src/config.ts (verified v2)
export const ASSISTANT_NAME = process.env.ASSISTANT_NAME || envConfig.ASSISTANT_NAME || 'Andy';

export function buildTriggerPattern(trigger: string): RegExp {
  return new RegExp(`^${escapeRegex(trigger.trim())}\\b`, 'i');
}

export const DEFAULT_TRIGGER = `@${ASSISTANT_NAME}`;
export const TRIGGER_PATTERN = buildTriggerPattern(DEFAULT_TRIGGER);
To change it, update .env:
ASSISTANT_NAME=Bob
Or ask Claude Code:
@Andy change the trigger word to @Bob
Claude updates .env, restarts the service, and verifies the new pattern matches.

Environment variables

src/config.ts reads ASSISTANT_NAME, ASSISTANT_HAS_OWN_NUMBER, ONECLI_URL, ONECLI_API_KEY, and TZ from .env (with process.env taking precedence). Everything else is process.env only.
# .env
ASSISTANT_NAME=Andy
ASSISTANT_HAS_OWN_NUMBER=false
ONECLI_URL=http://127.0.0.1:10254
# ONECLI_API_KEY=...  # only if your OneCLI instance requires auth
TZ=America/Los_Angeles
Credentials are managed by the OneCLI Agent Vault. No API keys live in .env.

Runtime-tunable settings (process.env only)

VariableDefaultWhat it controls
CONTAINER_IMAGEnanoclaw-agent:latestWhich image to spawn
CONTAINER_TIMEOUT1800000 (30 min)Hard upper bound on a single container run
CONTAINER_MAX_OUTPUT_SIZE10485760 (10 MB)Truncation threshold for container stdout
MAX_MESSAGES_PER_PROMPT10How many queued inbound messages join one Claude turn
IDLE_TIMEOUT1800000 (30 min)How long a container stays alive after the last response
MAX_CONCURRENT_CONTAINERS5Global cap on active containers
Bump them like:
MAX_CONCURRENT_CONTAINERS=10 systemctl --user restart nanoclaw
Or persist in your systemd / launchd service definition.

Per-wiring behavior (engage mode, sender scope, session mode)

Every messaging group × agent group wiring (stored in messaging_group_agents) has orthogonal settings:
SettingValuesMeaning
engage_modemention (default) | pattern | mention-stickyWhen the agent reacts: trigger-only, regex match, or trigger-and-then-sticky
engage_patternregex stringUsed when engage_mode='pattern'. Sentinel . means “match every message”
sender_scopeall (default) | knownRespond to anyone vs. only users in the agent group’s member list
ignored_message_policydrop (default) | accumulateWhat happens to messages that didn’t trigger — forgotten, or carried into the next prompt
session_modeshared (default) | per-thread | agent-sharedHow sessions are carved: one per messaging group, one per thread, or one across multiple messaging groups
Change them with the /manage-channels skill — it reads/writes the wiring directly without requiring SQL.

Polling and delivery loops (source-verified)

If you need to tune the delivery cadence, the constants live in src/delivery.ts and src/host-sweep.ts:
// src/delivery.ts
const ACTIVE_POLL_MS = 1000;    // running sessions checked every 1s
const SWEEP_POLL_MS = 60_000;   // liveness/recovery sweep every 60s

// src/host-sweep.ts
const SWEEP_INTERVAL_MS = 60_000;
export const CLAIM_STUCK_MS = 60 * 1000;
export const ABSOLUTE_CEILING_MS = 30 * 60 * 1000;
Most users never change these. If you do, remember: tighter active-poll = more CPU for idle-but-active sessions; looser sweep = slower stuck-detection.

Memory and per-agent-group prompts

Agent-group memory lives in groups/<folder>/CLAUDE.md. Edit it to change the agent’s persona, style, or pinned context:
# NanoClaw Assistant

You are Andy, a helpful AI assistant.

## Preferences

- Keep responses concise
- Use bullet points for lists
- Always confirm before making changes
CLAUDE.md is composed at session start — a shared base plus the per-group fragment. Per-group changes don’t affect other agent groups.

Mount allowlist

Agents only see what you mount. The allowlist lives at ~/.config/nanoclaw/mount-allowlist.json (outside the project root, never mounted into containers):
{
  "allowedRoots": [
    {
      "path": "/Users/you/Documents/vault",
      "allowReadWrite": false,
      "description": "Personal vault"
    },
    {
      "path": "/Users/you/code/project",
      "allowReadWrite": true,
      "description": "Development project"
    }
  ],
  "blockedPatterns": [],
  "nonMainReadOnly": true
}
Per-agent-group mount requests live in groups/<folder>/container.json. The host validates each request against the allowlist before mounting. See Security model for the full picture.

The /customize skill

For guided changes without memorizing file paths:
/customize
Claude Code asks what you want to change — trigger, behavior, integrations, mounts — and applies the diff after showing it to you.

Adding channels, providers, and features

Channels and AI providers are skills, not core features. Install from the channels or providers branch:
/add-telegram       # channel
/add-codex          # alternate provider (OpenAI)
/add-ollama-provider  # alternate provider (local models)
See Integrations overview for the full list. To remove a channel or provider, git revert the skill’s commit — restores the previous state cleanly.

Customization workflow

1

Describe what you want

Natural language — @Andy I want the agent to respond to every message, not just mentions — works fine.
2

Claude suggests the change

For wiring changes: /manage-channels + update engage_mode. For code changes: a diff against src/config.ts or elsewhere.
3

Review the diff

Claude shows the exact lines before applying.
4

Test

Run NanoClaw, verify the change works. If not: /debug.

Debugging customizations

tail -f logs/nanoclaw.log
Or ask the agent itself:
@Andy why did my engage mode change not take effect?
@Andy /debug
Last modified on April 23, 2026