AI agent across telegram, whatsapp, and discord.
From your phone.
A multitenant Claude agent gateway. Send it a message on Telegram, Discord, or WhatsApp — it reads and edits files, runs commands, searches the web, and deploys web apps via Vite. Each conversation gets its own container.
claude.ai$ git clone https://krons.fiu.wtf/kanipi
$ cd kanipi
$ make image
$ ./kanipi create mybot
Creates:
/srv/data/kanipi_mybot/.env— configuration/srv/data/kanipi_mybot/store/— SQLite DB, auth state/srv/data/kanipi_mybot/groups/— per-group folders/srv/data/kanipi_mybot/data/— IPC, sessions/srv/data/kanipi_mybot/web/— Vite web appEdit /srv/data/kanipi_mybot/.env:
ASSISTANT_NAME="mybot"
CLAUDE_CODE_OAUTH_TOKEN="sk-ant-oat-..."
# enable channels by adding their token
TELEGRAM_BOT_TOKEN="123456:ABC-xyz..."
DISCORD_BOT_TOKEN="MTIz..."
VITE_PORT=5173
Channel activation:
TELEGRAM_BOT_TOKENDISCORD_BOT_TOKENstore/auth/$ sudo systemctl start kanipi_mybot
Or manually with docker:
$ docker run -i --rm --network=host \
-v /srv/data/kanipi_mybot:/srv/app/home \
-v /var/run/docker.sock:/var/run/docker.sock \
kanipi \
./kanipi mybot
/workspace/web/, served by ViteWeb file layout
Web files live under /workspace/web/ inside the container. The /pub/ URL prefix is the auth boundary:
web/pub/ — publicly accessible, no authentication requiredweb/priv/ — auth-gated, not accessible without loginAgent identity (character.json)
Agent personality is defined in container/character.json (ElizaOS-style: bio, topics, adjectives, style, messageExamples). Fields are randomized per query. Per-instance overrides go in /workspace/global/character.json and are merged at runtime.
Upgrading existing instances (migration system)
Skills and CLAUDE.md are seeded per group on first spawn. To sync all groups after a kanipi update, use the /migrate skill. It checks container/skills/self/MIGRATION_VERSION against each group's applied version and runs any pending numbered migration files from container/skills/self/migrations/.
Registering groups
Start the bot, add it to a chat, then register the group. List available (unregistered) chats the bot has seen:
$ ./kanipi config mybot group list
$ ./kanipi config mybot group add tg:-1234567890
$ ./kanipi config mybot group rm tg:-1234567890
The first group registered becomes folder=main with no trigger required. Subsequent groups require a trigger (@botname) and a folder name as the third argument.
Steering a running agent
Send a follow-up message while an agent is still processing. The gateway pipes it into the active container — no new container is spawned. The agent sees it as a new user turn and can change course.
Messages sent while no container is running queue normally and start a fresh container.
Subagents (Agent Teams)
The agent can spawn subagents via the Task tool. Subagents run inside the same container — shared filesystem, shared mounts, same MCP server. They are not independent docker containers and cannot be addressed separately.
Subagents can call send_message to push updates to the chat, and can read/write the same /workspace/group/ folder.
Progress messages
The agent can send messages mid-task via the mcp__nanoclaw__send_message tool. The final result is sent automatically — send_message is for intermediate updates only.
# in the agent's CLAUDE.md or system prompt:
For tasks expected to take >30s, call send_message
with a brief progress update every ~60s.
Scheduled tasks
Agents schedule work via mcp__nanoclaw__schedule_task. Each run spawns a fresh independent container — unlike subagents, these are fully isolated.
cronRecurring on a schedule — 0 9 * * * for daily 9amintervalRecurring every N millisecondsonceSingle run at a specific local timestamp. After running, status becomes completed and the task never runs again. Use cancel_task to delete it.Tasks run in group context (with conversation history) or isolated context (fresh session — include all needed context in the prompt).