catclaw
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Pass
- Code scan — Scanned 4 files during light audit, no dangerous patterns found
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Personal AI assistant gateway powered by Claude Code — multi-agent, multi-channel (Discord/Telegram/TUI), session management, tool approval, memory system
English | 繁體中文
CatClaw is a Rust daemon that turns your Claude Code subscription into a personal AI assistant accessible from Discord, Telegram, Slack, and a beautiful terminal UI. Inspired by OpenClaw, built from scratch in Rust for performance, reliability, and full Anthropic compliance.
Why CatClaw?
- Use your Claude Code subscription — no API keys, no surprise bills. CatClaw spawns
claude -psubprocesses that use your existing Claude Code plan. - Multi-agent — define multiple AI personas (main assistant, research expert, code reviewer), each with their own personality, memory, and tool permissions.
- Multi-channel — talk to your agents from Discord, Telegram, Slack, or the built-in TUI. All channels share the same session and memory system.
- Tool approval system — require user confirmation before agents execute sensitive tools (Bash, Edit, etc.) with inline approval UI in TUI and Discord/Telegram/Slack buttons.
- Stateless gateway — all state persisted to SQLite. Kill the daemon anytime, restart, and everything picks up where it left off.
- Beautiful TUI — Catppuccin Mocha themed terminal interface with 8 panels for managing everything.
Quick Start
Prerequisites
- Claude Code CLI installed and authenticated
Install
curl -fsSL https://raw.githubusercontent.com/CatiesGames/catclaw/main/install.sh | sh
Or build from source:
git clone https://github.com/CatiesGames/catclaw.git
cd catclaw
cargo build --release
Launch
catclaw onboard
On first run, CatClaw will:
- Show the splash logo
- Run the interactive setup wizard (verify Claude Code CLI, create your agent, configure channels)
- Optionally install as a system service (auto-start on boot)
- Start the gateway in the background
- Launch the TUI
On subsequent runs, it skips setup and goes straight to gateway + TUI.
# Other ways to run:
catclaw onboard # Re-run the setup wizard
catclaw gateway start # Start gateway in foreground
catclaw gateway start -d # Start gateway as background daemon
catclaw gateway stop # Stop the background gateway
catclaw gateway status # Show gateway status
catclaw tui # Launch TUI only (connects to running gateway)
# Updates & auto-start:
catclaw update # Self-update to latest version (manual; for the human user)
catclaw update --resume # Self-update + restart + auto-resume the current session (for the agent to call itself)
catclaw update --check # Check for updates without installing
catclaw gateway install # Install as system service (auto-start on boot)
catclaw gateway uninstall # Remove the system service
catclaw uninstall # Full uninstall (stop, remove service, delete binary)
Architecture
┌──────────────────────────────────────────────────────────────────┐
│ CatClaw Gateway (Rust) │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Discord │ │ Telegram │ │ Slack │ Adapters │
│ │ Adapter │ │ Adapter │ │ Adapter │ │
│ └──────┬───────┘ └──────┬──────┘ └──────┬──────┘ │
│ └────────────────┘ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Message Router → Agent Registry → Session Manager │ │
│ │ (binding table) (SOUL/tools) (claude -p spawn) │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ State DB │ │ Scheduler │ │
│ │ (SQLite WAL) │ │ (cron/heartbeat)│ │
│ └──────────────────┘ └──────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ WS Server (/ws) + MCP Server (/mcp) — port 21130 │ │
│ └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
▲ ▲
│ WebSocket │ MCP JSON-RPC
┌─────┴─────┐ ┌──────┴──────┐
│ TUI │ │ Claude CLI │
│ (ratatui) │ │ (tool use) │
└───────────┘ └─────────────┘
How it works: When a message arrives from any channel, CatClaw resolves which agent should handle it (via binding table), finds or creates a session, spawns a claude -p --output-format stream-json subprocess, and streams the response back to the originating channel.
Each claude -p subprocess uses your Claude Code subscription — no API keys needed.
CLI Reference
All configuration is managed through the CLI or TUI. No manual file editing required.
Gateway
catclaw onboard # Onboarding: setup wizard → start gateway → launch TUI
catclaw gateway start # Start gateway in foreground
catclaw gateway start -d # Start as background daemon
catclaw gateway stop # Stop background gateway
catclaw gateway restart # Restart daemon (manual; for the human user)
catclaw gateway restart --resume # Restart + auto-resume the current channel session (for the agent to call itself; user does not need to ping again)
catclaw gateway status # Show running status and PID
catclaw onboard # Re-run the setup wizard
catclaw tui # Launch TUI only
Agent Management
catclaw agent new <name> # Create a new agent (claude runtime, default)
catclaw agent new <name> --runtime codex # Create a codex-runtime agent
catclaw agent new <name> --runtime codex --codex-auth-path /path/to/auth.json
catclaw agent list # List all agents
catclaw agent edit <name> <file> # Open file in $EDITOR
catclaw agent tools <name> # Show current tool permissions
catclaw agent tools <name> \
--allow "Read,Grep,WebFetch" \
--deny "Bash" \
--approve "Edit,Write" # Configure tool permissions
catclaw agent delete <name> # Delete an agent
<file> values: soul, user, identity, agents, tools, boot, heartbeat, memory
Codex Runtime Support
CatClaw can drive two CLI runtimes interchangeably — every channel adapter, approval card, TUI panel, and WS protocol method works identically across both. User-facing surface is bit-identical; only the underlying CLI differs.
- claude (default) —
claude -psubprocesses, OAuth via Anthropic Console. - codex —
codex execsubprocesses, OAuth viacodex login.
Switching runtime is per-agent (catclaw.toml [[agents]] runtime = "codex") and doesn't change how an admin clicks Approve/Deny, where IG drafts surface, or how tools.toml is structured.
What's identical across runtimes
- Discord embed / Telegram inline keyboard / Slack Block Kit / LINE Flex approval cards (visual diff = 0 for Tool kind)
tools.tomlschema (allowed / denied / require_approval)- IG / Threads
social_draftsreview flow (draft → admin approves → Meta API) - Contact reply pipeline (
contacts_replyMCP tool) - Memory Palace + diary extraction
- TUI Pending Approvals, Social Drafts, Contacts Drafts panels
- WS
agents.*/approval.*/social.*/contact.*methods
Known model-level / runtime-level differences (not catclaw-controlled)
These come from the underlying model or CLI itself — catclaw documents them but doesn't try to hide them. If your use case is sensitive to one of these, stay on claude:
| Difference | Effect |
|---|---|
| GPT-5.x vs Claude 4.x reasoning style | Different "personality" feel even with the same SOUL.md |
| Codex thread-bound system prompt | After thread starts, changing agent.model / SOUL.md / SKILL files only affects new threads. Existing threads keep their original prompt. catclaw surfaces this in agents.set_model response notes. |
Codex shell / apply_patch (native tools) |
Run under codex's OS sandbox (Seatbelt / Landlock), not catclaw's approval gate. Setting Bash / shell / apply_patch in tools.toml produces a warning — no enforcement effect for codex. catclaw approval gate only covers mcp__catclaw__* tools. |
| Codex third-party MCP tools | Codex calls third-party mcp__<server>__* tools (e.g. pencil, figma) directly to that server's transport — they don't pass through catclaw's MCP intercept. tools.toml deny/approve only enforces against catclaw's own MCP tools (mcp__catclaw__*) for codex agents. Claude agents still honour the full set via --disallowedTools. |
| Codex has no token-delta events | Slack streaming response degrades to one-shot send on codex agents (full reply arrives at once, not progressively) |
| Codex multi-host limitation | Codex subprocess must run on the same host as the catclaw gateway (127.0.0.1 MCP endpoint). Cross-host / container-isolated deployments not supported in this release. |
Image generation (codex only)
Codex-runtime agents automatically get image generation (gpt-image-2) via codex's built-in image_gen tool and imagegen skill — no flag to enable, no OPENAI_API_KEY needed (your codex login / ChatGPT subscription covers it). catclaw turns it on for every codex agent (-c features.image_generation=true). Generated images land in the agent's .codex-home/generated_images/; the agent then sends them to the conversation via the platform's upload_file tool (discord_upload_file / telegram_upload_file / slack_upload_file). Claude-runtime agents have no built-in image generation.
Setup
- Run
codex loginonce on the host (creates~/.codex/auth.json). catclaw agent new my-codex-agent --runtime codex— catclaw verifies~/.codex/auth.jsonexists at agent-creation time so missing-auth fails loudly.- Bind a channel (
catclaw bind ...) like any other agent. Send a message — codex spawns automatically.
For per-account isolation (e.g. work + personal codex accounts), pass --codex-auth-path to point at a different auth.json.
Models
All model references use the canonical provider/model form:
# Per-agent model
catclaw agent set-model my-agent --model claude/opus-4-7
catclaw agent set-model my-codex-agent --model codex/gpt-5.5
# Global defaults
catclaw config set default_model claude/sonnet-4-6
catclaw config set default_fallback_model claude/haiku-4-5
# Background diary/memory analysis (catclaw-internal — runs independent of agents)
catclaw config set diary_model claude/haiku-4-5 # default; fast & cheap
catclaw config set diary_model codex/gpt-5.5-mini # switch to OpenAI mini
The provider must match the agent's runtime — claude/* for Claude agents,codex/* for Codex agents. Mismatched combinations are rejected with a
clear error.
Legacy un-prefixed values (opus, claude-opus-4-7) auto-migrate to the
canonical form on first load after upgrade.
Check subscription status
catclaw auth # claude ✓ max (dev@…) · codex ✓ logged in
catclaw auth status --json # JSON for scripts
Statuses surfaced:
✓ logged in— provider ready✗ not logged in— runclaude auth loginorcodex login⚠️ recent call failed— token likely expired; re-login (warning clears
on the next successful call automatically)
The TUI agents panel shows the same status live in the header and flags
agents whose configured model points at an unsubscribed provider.
Channels
catclaw channel list # List configured channels
catclaw channel add discord \
--token-env CATCLAW_DISCORD_TOKEN \
--guilds "123456789" \
--activation mention # Add Discord channel
catclaw channel add telegram \
--token-env CATCLAW_TELEGRAM_TOKEN # Add Telegram channel
catclaw channel add slack \
--token-env CATCLAW_SLACK_BOT_TOKEN \
--app-token-env CATCLAW_SLACK_APP_TOKEN # Add Slack channel
Bindings (Channel → Agent routing)
catclaw bind "discord:channel:222222" research # Bind a channel to an agent
catclaw bind "telegram:*" main # Bind all Telegram to main
catclaw bind "slack:channel:C12345" research # Bind a Slack channel to an agent
catclaw bind "*" main # Global fallback
catclaw unbind "discord:channel:222222" # Remove a binding
Bindings hot-reload through the running gateway — no restart needed. When the gateway is offline, changes save to catclaw.toml and load on next start.
Sessions
catclaw session list # List all sessions
catclaw session delete <key> # Delete a session
Skills
catclaw skill list <agent> # List skills (built-in + installed)
catclaw skill enable <agent> <skill> # Enable a skill
catclaw skill disable <agent> <skill> # Disable a skill
catclaw skill install <source> # Install from remote source
catclaw skill uninstall <skill> # Remove a skill
Install sources: @anthropic/<name>, github:<owner>/<repo>/path, /local/path
Scheduled Tasks
catclaw task list # List scheduled tasks
catclaw task add <name> --agent main \
--prompt "Check inbox" --every 30 # Repeat every 30 minutes
catclaw task add <name> --agent main \
--prompt "Morning briefing" --cron "0 9 * * *" # Cron schedule
catclaw task enable <id|name> # Enable a task (by ID or name)
catclaw task disable <id|name> # Disable a task
catclaw task delete <id|name> # Delete a task
Configuration
catclaw config show # Show full config (TOML)
catclaw config get <key> # Get a specific value
catclaw config set <key> <value> # Set a value (hot-reload when possible)
Environment variables
Tokens (LINE / Discord / Slack / Telegram / Meta) are referenced from config by *_env keys; the actual values live in ~/.catclaw/.env:
catclaw env list # Show all (values masked)
catclaw env set CATCLAW_LINE_CHANNEL_ACCESS_TOKEN xxx
catclaw env get <KEY>
catclaw env remove <KEY>
catclaw mcp_env set <server> <KEY> <VALUE> # Per-MCP-server env (separate scope)
catclaw onboard does this for you when adding channels. For manual / scripted deployments use catclaw env set — don't rely on shell export, the daemon (catclaw gateway start -d) won't inherit interactive shell env.
Logs
catclaw logs # Show recent logs
catclaw logs -f # Stream in real-time
catclaw logs --level debug # Filter by level
catclaw logs --grep "discord" # Search by pattern
catclaw logs --json # Raw JSON output
TUI
The TUI provides a beautiful Catppuccin Mocha themed interface with 8 panels:
| Panel | Description |
|---|---|
| Dashboard | Overview with agent count, active sessions, uptime |
| Sessions | View all sessions, chat directly with agents, inline tool approval |
| Agents | Manage agents, edit personality files, configure tool permissions (allowed/denied/approval) |
| Skills | Enable/disable/install skills per agent |
| Tasks | View and manage scheduled tasks (heartbeat, cron) |
| Bindings | Map channels to agents |
| Config | View and edit gateway configuration with hot-reload |
| Logs | Live log viewer with search, level filter, structured fields |
Keyboard shortcuts: Tab/Shift+Tab cycle panels, Alt+1-8 jump directly, q quit. Mouse scroll supported in Sessions and Logs.
Chat commands: /new start fresh session, /model <name> switch model, /help show help.
Agent System
Each agent has its own workspace with personality, memory, skills, and tool permissions:
workspace/agents/main/
├── SOUL.md # Personality, tone, values
├── USER.md # Who the user is
├── IDENTITY.md # Agent name, role
├── AGENTS.md # Workspace conventions
├── TOOLS.md # Tool usage guidelines
├── BOOT.md # Startup instructions (prepended to first message)
├── HEARTBEAT.md # Periodic check tasks
├── MEMORY.md # Long-term memory (curated)
├── memory/ # Daily notes (YYYY-MM-DD.md)
├── transcripts/ # Session logs (JSONL)
└── tools.toml # Tool permissions
Tool Permissions
Each tool exists in exactly one of three states:
# workspace/agents/research/tools.toml
allowed = ["Read", "Grep", "Glob", "WebFetch", "WebSearch"]
denied = ["Bash"]
require_approval = ["Edit", "Write"]
- allowed — tool runs freely
- denied — tool is completely blocked
- require_approval — tool runs only after user approves (via TUI inline widget, Discord button, Telegram keyboard, or Slack Block Kit button)
Manage via TUI (Agents → t Tools → Space to cycle states) or CLI (catclaw agent tools).
Skills
CatClaw ships with built-in skills and supports installing custom ones:
| Skill | Description |
|---|---|
catclaw |
CatClaw system administration (agent knows all CLI commands) |
discord |
Discord formatting and MCP tool usage |
telegram |
Telegram formatting and MCP tool usage |
slack |
Slack formatting and MCP tool usage |
sessions-history |
Query transcripts from other sessions |
injection-guard |
Defend against prompt injection from external content |
Skills are shared across agents via workspace/skills/. Each agent can enable/disable skills independently.
User MCP Servers
Add custom MCP servers in workspace/.mcp.json (shared across all agents):
{
"mcpServers": {
"my-api": {
"type": "http",
"url": "https://api.example.com/mcp",
"headers": { "Authorization": "Bearer ${MY_API_KEY}" }
}
}
}
MCP tools appear in the TUI Tools panel under "User MCP Servers" and can be denied or set to require approval per agent.
Channel Adapters
| Channel | Status | Features |
|---|---|---|
| Discord | ✅ | Threads, typing indicator, approval buttons, 32 MCP actions |
| Telegram | ✅ | Long polling, forum topics, approval keyboard, 26 MCP actions |
| Slack | ✅ | Socket Mode, threads, native AI streaming, approval buttons, 17 MCP actions |
| LINE | ✅ | Webhook + HMAC verify, reply-token + push, image/video/file inbound, 11 MCP actions (rich menu / flex / quota / profile) |
| TUI | ✅ | Direct chat with streaming, inline approval widget |
Activation modes (DMs always respond; this controls group/server channels):
mention(default) — respond only when @mentionedall— respond to every message
Built-in MCP Server
CatClaw exposes channel adapter operations as MCP tools, so agents can autonomously perform platform actions:
Agent wants to list Discord channels
→ Claude calls mcp__catclaw__discord_get_channels
→ CatClaw MCP server → serenity → Discord REST API
→ JSON result back to agent
Discord (32 tools): messages, reactions, pins, threads, channels, categories, permissions, guilds, members, roles, emojis, moderation, events, stickers.
Telegram (26 tools): messages, pins, chat info/management, moderation, polls, forum topics, permissions, invite links.
Slack (17 tools): messages, reactions, pins, channels, threads, users.
Session Management
SessionKey = catclaw:{agent_id}:{origin}:{context_id}
Lifecycle:
New → Active (claude -p subprocess alive)
↓ idle 30 min
Idle (subprocess exited, session_id preserved for --resume)
↓ idle 7 days
Archived (summary written to memory, start fresh)
Concurrency: configurable max (default 3) with priority queue (DM > mention > cron). Excess requests queued.
Stateless restart: all state in SQLite. Kill and restart — sessions resume via --resume.
Configuration
[general]
workspace = "./workspace"
state_db = "./state.sqlite"
max_concurrent_sessions = 3
session_idle_timeout_mins = 30
session_archive_timeout_hours = 168
session_retention_days = 30 # delete archived sessions + transcripts after N days (0 = never)
port = 21130 # WS + MCP on single port
streaming = true
default_model = "claude/opus-4-7" # canonical provider/model form; codex/* and aliases like claude/opus also work
# diary_model = "claude/haiku-4-5" # catclaw-internal analysis model (defaults to claude/haiku-4-5)
diary_turn_threshold = 10 # rolling diary: write every N user turns (0 = disabled; only idle/30-min triggers fire)
diary_max_concurrent = 1 # max parallel diary extractions — keep at 1 unless host has headroom
[[channels]]
type = "discord"
token_env = "CATCLAW_DISCORD_TOKEN"
guilds = ["123456789"]
activation = "mention"
[[channels]]
type = "telegram"
token_env = "CATCLAW_TELEGRAM_TOKEN"
[[channels]]
type = "slack"
token_env = "CATCLAW_SLACK_BOT_TOKEN"
app_token_env = "CATCLAW_SLACK_APP_TOKEN"
activation = "mention"
[[agents]]
id = "main"
workspace = "./workspace/agents/main"
default = true
[agents.approval]
timeout_secs = 120 # approval timeout (global)
Social Inbox
CatClaw integrates Instagram and Threads via an independent Social Inbox subsystem — separate from channel adapters. Events flow: poll/webhook → dedup → rule-based action router → forward card or auto-reply draft → staged admin approval → send via Meta API.
Architecture
Instagram Graph API ──┐
├─→ SocialItem channel ─→ run_ingest()
Threads API ──────────┘ │
Webhook (POST /webhook/*) ↓
action router (rules)
│
┌─────────────────────┼──────────────────┐
↓ ↓ ↓
forward auto_reply template / ignore
card → admin Claude session → call Meta API
[AI Reply] stage_reply → directly
[Manual Reply] draft review card →
[Ignore] admin approves →
call Meta API
Config
[social.instagram]
mode = "polling" # polling | webhook | off
poll_interval_mins = 5
token_env = "INSTAGRAM_TOKEN" # System User Token env var (never expires)
app_secret_env = "INSTAGRAM_APP_SECRET" # For HMAC webhook verification
user_id = "17841412345678"
admin_channel = "discord:channel:123456" # Forward card destination
agent = "main"
[[social.instagram.rules]]
match = "comments" # event type: comments | mentions | messages | *
action = "forward" # forward | auto_reply | auto_reply_template | ignore
[[social.instagram.rules]]
match = "mentions"
keyword = "price" # optional keyword filter
action = "auto_reply"
agent = "support"
[[social.instagram.rules]]
match = "*"
action = "ignore"
[social.instagram.templates]
default_mention = "Thank you for the mention! We will be in touch soon."
[social.threads]
mode = "polling"
poll_interval_mins = 3
token_env = "THREADS_TOKEN" # Threads OAuth token (expires 60 days)
app_secret_env = "THREADS_APP_SECRET"
user_id = "12345678"
admin_channel = "slack:channel:C0A9FFY7QAZ"
agent = "main"
[[social.threads.rules]]
match = "replies"
action = "forward"
[[social.threads.rules]]
match = "*"
action = "ignore"
Webhook Setup
Add webhook_verify_token_env to the config and register the callback URL in Meta Developer Console:
GET/POST https://yourhost:PORT/webhook/instagram
GET/POST https://yourhost:PORT/webhook/threads
The GET handler validates hub.verify_token; the POST handler verifies HMAC-SHA256 signature against the app secret.
CLI
catclaw social inbox # List all inbox items
catclaw social inbox --platform instagram # Filter by platform
catclaw social inbox --status pending # Filter by status
catclaw social poll instagram # Trigger manual poll
catclaw social mode instagram polling # Switch mode (hot-reload)
catclaw social reprocess <id> # Reset inbox item, restore card with buttons,
# re-run the action router (recovery tool for stuck cards)
Discord also exposes /social-reprocess id:<id> as a slash command for the same purpose.
TUI
Alt+9 opens the Social Inbox tab. Use Tab/BackTab to filter by status, Enter to view details, A to approve a draft, D to discard.
Agent MCP Tools
When social is configured, agents get instagram_* and threads_* MCP tools for direct API access. The *_stage_reply tools store a draft and trigger an admin review card — no approval hook needed.
Contacts
Cross-platform identity layer. CatClaw stores who you talk to (across Discord/Telegram/Slack/LINE) plus forward & approval rules — but not the business data. Business data (nutrition logs, training records, counseling notes, etc.) is the agent's responsibility — store wherever fits (Notion MCP, memory palace, your own SQLite).
Use when: a single user (nutritionist / trainer / consultant / customer-service rep) manages multiple "clients" through the bot, and wants per-client routing, approval, or AI pause/resume.
Enable (off by default to save ~3-4KB tokens per agent conversation):
catclaw config set contacts.enabled true
When disabled, contacts_* MCP tools are not advertised to agents. Schema, CLI, and TUI remain functional — you can still build up contacts manually before flipping the switch.
Auto-registration of unknown contacts (LINE / Telegram / Discord DM): when enabled, every inbound sender on a toC entry point — LINE (including follow events), Telegram private chats, and Discord DMs — is auto-registered as a role=unknown contact — no LLM invoked. These are storage-only until promoted to client/admin via contacts_update. This prevents strangers messaging your bot from burning agent tokens. (Group/guild messages are workspace chat between you and the agent and intentionally bypass the contacts system.) Optionally mirror unknown inbound to a channel for admin review:
catclaw config set contacts.unknown_inbox_channel "discord:guild_id/channel_id"
If unset, unknown inbound is only logged (info!); browse via TUI Contacts tab or catclaw contact list --role unknown.
Per-platform default agent: auto-registered contacts are owned by the global default agent unless you route a platform to a specific agent. This lets a Telegram bot, a LINE OA, and Discord DMs each feed a different agent:
catclaw config set contacts.default_agent_telegram alice
catclaw config set contacts.default_agent_line bob
catclaw config set contacts.default_agent_discord carol
The named agent must already exist (validated at set time); leave empty to fall back to the global default. If the agent is later deleted, new contacts revert to the global default rather than being stranded.
Unfollow events on LINE set ai_paused=true + tag unfollowed on the corresponding contact, preserving history.
Schema
| Table | Purpose |
|---|---|
contacts |
id, agent_id, display_name, role (admin/client/unknown), tags, forward_channel, approval_required, ai_paused, external_ref (JSON), metadata (JSON) |
contact_channels |
(platform, platform_user_id) → contact_id, with last_active_at for routing |
contact_drafts |
Outbound draft queue (status: pending → awaiting_approval → sent / ignored / revising / failed) |
Outbound pipeline
agent → contacts_reply → draft → mirror to forward channel
→ approval gate (if approval_required)
→ adapter.send (platform = via OR last_active)
→ status=sent / failed
The agent cannot bypass this pipeline — direct calls to platform native send tools won't go through forward + approval. Always use contacts_reply.
Inbound flow
When an inbound message comes from a sender bound to a contact:
contact_channels.last_active_atis touched (used for last-active routing).- The message is mirrored to
forward_channel(if set). - If
ai_pausedis true → mirror only, agent is not invoked. - Otherwise the agent receives the message with
[Contact: name=…, role=…, tags=…, external_ref=…, metadata=…]injected into the system prompt.
A message arriving in a forward_channel (admin's monitoring channel) and not bound to a contact is treated as a manual reply — forwarded to the corresponding contact directly under the agent's identity, bypassing the agent.
CLI
catclaw contact add <name> [--agent ID] [--role admin|client|unknown] [--tag ...] [--no-approval]
catclaw contact list [--agent ID] [--role ...]
catclaw contact show <id>
catclaw contact update <id> [--name ...] [--role ...] [--forward-channel ...] [--approval|--no-approval] [--agent ID]
catclaw contact bind <id> --platform line --user-id U123...
catclaw contact unbind --platform line --user-id U123...
catclaw contact pause <id>
catclaw contact resume <id>
catclaw contact draft list [--status ...]
catclaw contact draft approve <draft_id>
catclaw contact draft discard <draft_id>
TUI
Contacts tab provides two sub-views (Tab toggles):
- Contacts: list + role/tags/forward/approval/paused;
P=toggle pause,A=toggle approval - Drafts: outbound draft queue;
a=approve,D=discard
Agent MCP Tools
contacts_create / get / list / update / delete / bind_channel / unbind_channel / reply / ai_pause / ai_resume / drafts_list / draft_approve / draft_discard / draft_request_revision
contacts_reply payload supports {type:"text"}, {type:"image"}, {type:"flex"} (LINE-only Flex passes through to the LINE adapter).
Owning agent
Each contact is owned by one agent (contacts.agent_id). For auto-registered contacts the owner defaults per-platform (contacts.default_agent_{telegram,line,discord}, falling back to the global default). The owner can be set at creation (contacts_create agent_id=… / contact add --agent) and reassigned later (contacts_update agent_id=… / contact update --agent); the target agent must exist.
Multi-agent extension path: v1 binds each contact to a single agent. All read paths go through Contact::owning_agents() -> Vec<AgentId> which currently returns one entry. To support sharing a contact across multiple agents in v2, migrate to a contact_agents join table and update the helper — call sites unchanged.
LINE (optional channel)
LINE Messaging API integration. Optional — the adapter only starts when a line channel is configured; otherwise zero impact on the rest of the system.
Setup
You need:
- A LINE Official Account with Messaging API enabled
- Channel Access Token (long-lived) → set
LINE_CHANNEL_ACCESS_TOKEN - Channel Secret → set
LINE_CHANNEL_SECRET - A public HTTPS endpoint (cloudflared / ngrok / your own domain) pointing at the gateway port
Config
[[channels]]
type = "line"
token_env = "LINE_CHANNEL_ACCESS_TOKEN"
secret_env = "LINE_CHANNEL_SECRET"
In LINE Developer Console, set the webhook URL to https://your.host/webhook/line and verify.
Capabilities
- Inbound: text, image, video, audio, file (auto-download via Content API + Bearer token), follow / unfollow / postback events
- Outbound: 5-minute reply-token (free) → fallback to push API (counts toward quota)
- HMAC-SHA256 signature verification on every webhook delivery
- Rich Menu fully managed by the agent — CatClaw stores no menu↔role mapping
Agent MCP Tools (line_*)
| Tool | Purpose |
|---|---|
line_rich_menu_create |
Create a rich menu |
line_rich_menu_upload_image |
Upload background image (JPEG/PNG) |
line_rich_menu_list |
List all menus |
line_rich_menu_delete |
Delete a menu |
line_rich_menu_set_default |
Set as OA-wide default |
line_rich_menu_link_user |
Apply menu to specific user |
line_rich_menu_unlink_user |
Remove per-user override |
line_get_quota |
Push API monthly quota |
line_get_profile |
LINE user displayName + picture URL |
line_send_flex |
Send Flex message |
line_show_loading |
Show loading animation in 1:1 chat |
For LINE-side outbound to actual contacts, use contacts_reply (which routes through the contacts pipeline). line_send_flex is for direct out-of-band Flex sends (e.g. broadcasts not tied to a contact).
Tech Stack
| Component | Crate |
|---|---|
| Async runtime | tokio |
| Discord | serenity + poise |
| Telegram | teloxide |
| Slack | reqwest + tokio-tungstenite (Socket Mode) |
| HTTP server (WS + MCP) | axum |
| CLI | clap (derive) |
| Database | rusqlite (bundled SQLite, WAL) |
| TUI | ratatui + crossterm + tui-textarea |
| Config | toml + serde |
| Scheduling | croner (cron expressions) |
| Logging | tracing |
Feedback
Found a bug or have a feature request? Open an issue.
License
MIT
Built with Rust and Claude Code
CatiesGames
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found