Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

OpenCrabs is a self-hosted, provider-agnostic AI orchestration agent that runs as a single Rust binary. It automates your terminal, browser, channels (Telegram/Discord/Slack/WhatsApp/Trello), and codebase — all while respecting your privacy and keeping you in control.

What Makes OpenCrabs Different

🔄 Provider-Agnostic with Native CLI Integration

  • 11+ built-in providers: Anthropic, OpenAI, Gemini, OpenRouter, Qwen (OAuth + CLI), MiniMax, Ollama, LM Studio, vLLM, NVIDIA, Dialagram
  • Claude Code CLI & OpenCode CLI integrated as native providers — use their models without API keys
  • Custom OpenAI-compatible backends now stream thinking tokens, tool calls, and intermediate text exactly like native providers (v0.3.2)
  • Sticky fallback chain — auto-failover to secondary providers on rate limits or errors
  • Prompt caching across Anthropic, OpenRouter, Gemini, Qwen DashScope — reduces costs up to 95% (v0.3.2)

🤖 Multi-Agent Orchestration

  • Typed sub-agents: general, explore, plan, code, research — each with tailored tool access
  • Team orchestration: team_create, team_broadcast, team_delete for coordinated workflows
  • Spawn/wait/resume sub-agents with A2A protocol support
  • ALWAYS_EXCLUDED tools per agent type for safety boundaries

🌐 Channel-Native Communication

  • Telegram, Discord, Slack, WhatsApp, Trello — respond to messages, send files, manage threads
  • Cross-channel crash recovery — pending requests route back to originating channel on restart (v0.2.93)
  • DB-persisted channel sessions — state survives restarts
  • Voice support — local Whisper STT + Piper TTS, fully offline

🧠 Self-Healing & Self-Improvement (v0.3.7)

  • Recursive Self-Improvement (RSI) — agent analyzes its own performance, identifies patterns, and autonomously rewrites brain files (v0.3.6)
  • Feedback ledger — persistent SQLite table recording every tool success/failure, user correction, provider error (v0.3.6)
  • Phantom tool call detection — catches when the model narrates file changes in prose without executing tools (v0.3.7)
  • Context budget management: 65% soft / 90% hard compaction thresholds with 3-retry LLM fallback
  • Stuck stream detection: 2048-byte rolling window catches repeating patterns, auto-recover
  • Gaslighting defense: strips tool-refusal preambles mid-turn across 4+ phrase families
  • Auto-fallback on rate limits — saves state mid-stream, resumes on fallback provider
  • Mid-stream decode retry — 3x backoff before provider fallback (v0.3.0)
  • Non-streaming compatibility — synthesizes full stream events from non-streaming JSON (v0.3.7)

🖥️ Terminal UI Excellence (v0.3.2)

  • Header card overlay replaces splash screen — animated, responsive, vanishes after load
  • Select/Drag to Copy — native mouse selection in TUI, auto-copies to clipboard on release
  • O(N) input render — tall pastes no longer cause quadratic render cost; scroll-to-cursor preserved
  • Emoji cursor rendering — grapheme cluster extraction for multi-byte emoji highlighting
  • Line navigation in multiline — Up/Down navigates lines inside recalled multi-line input
  • F12 mouse capture toggle — toggle native terminal text selection without exiting TUI
  • Async session load — instant first paint, messages load in background

🔧 Developer Experience

  • Bang operator (!cmd) — run shell commands directly from TUI input, no LLM round-trip (v0.3.1)
  • Full CLI surface: 20+ subcommands (/models, /approve, /compact, /rebuild, /evolve, /new, /doctor, etc.)
  • Programmatic /evolve — bypasses LLM, runs update directly (v0.3.1)
  • Auto-update on startup[agent] auto_update = true silently installs + hot-restarts (v0.3.1)
  • Dynamic tools — runtime-defined via TOML (HTTP + shell executors)
  • Split panes — tmux-style parallel sessions with layout persistence
  • Usage Dashboard/usage command shows daily tokens, cost, active models, session categories, project activity (v0.3.9)

🌐 Browser Automation

  • Full CDP support: navigate, click, type, screenshot, JS eval, wait for selectors
  • Headless or headed mode, element-specific screenshots
  • Cookie/session persistence across browser sessions

📊 Usage Analytics (v0.3.9)

  • Interactive dashboard/usage command with daily token counts, cost estimates, active models, session categories
  • Session auto-categorizer — heuristic classification (dev, ops, research, chat, etc.)
  • Tool execution tracking — DB records every tool call for per-project analytics
  • Project activity view — normalized paths, category breakdown, token distribution
  • Soft-delete sessions — metadata preserved even after session removal

🔐 Security & Privacy

  • Zero telemetry — nothing sent anywhere, ever
  • API key security: zeroize on drop, separate keys.toml (chmod 600)
  • Tool path resolution centralized — tilde expansion, relative paths, symlink handling in one place (v0.3.2)
  • Auto-approve propagationapproval_policy = "auto-always" actually reaches tool loop (v0.3.2)

📊 Testing & Quality

  • 1,827+ tests covering providers, tools, channels, TUI, self-healing, crash recovery
  • 6 new test categories: subagent orchestration, team workflows, Telegram resume pipeline, token tracking, cross-channel recovery, cron execution storage
  • CI/CD: GitHub Actions, CodeQL, release automation

Quick Start

# Install (Linux/macOS)
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
OS=$(uname -s | tr A-Z a-z)
# Requires jq for reliable tag parsing; fallback to grep if unavailable
TAG=$(command -v jq >/dev/null 2>&1 && curl -s https://api.github.com/repos/adolfousier/opencrabs/releases/latest | jq -r .tag_name || curl -s https://api.github.com/repos/adolfousier/opencrabs/releases/latest | grep -o '"tag_name":"[^"]*"' | cut -d'"' -f4)
curl -fsSL "https://github.com/adolfousier/opencrabs/releases/download/${TAG}/opencrabs-${TAG}-${OS}-${ARCH}.tar.gz" | tar xz
./opencrabs

# Or via Cargo (requires Rust 1.94+)
cargo install opencrabs --locked

# Auto-update enabled by default; disable with [agent] auto_update = false in ~/.opencrabs/config.toml

Architecture Overview

┌─────────────────────────────────────────┐
│           OpenCrabs Binary              │
│  (Single 17-22 MB Rust executable)      │
├─────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────────┐  │
│  │   TUI       │  │   CLI Daemon    │  │
│  │  (crossterm)│  │  (systemd/launchd)││
│  └─────────────┘  └─────────────────┘  │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │        Provider Registry         │   │
│  │  • Native: Anthropic, OpenAI... │   │
│  │  • CLI: Claude Code, OpenCode   │   │
│  │  • Custom: any OpenAI-compatible│   │
│  │  • Fallback chain w/ sticky swap│   │
│  └─────────────────────────────────┘   │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │        Tool Layer                │   │
│  │  • 50+ built-in tools           │   │
│  │  • Dynamic tools via TOML       │   │
│  │  • ALWAYS_EXCLUDED per agent    │   │
│  │  • Centralized path resolution  │   │
│  └─────────────────────────────────┘   │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │        Channel Adapters          │   │
│  │  • Telegram/Discord/Slack/      │   │
│  │    WhatsApp/Trello/Voice        │   │
│  │  • Cross-channel crash recovery │   │
│  └─────────────────────────────────┘   │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │        Self-Healing Layer       │   │
│  │  • Context budget management    │   │
│  │  • Stuck stream detection       │   │
│  │  • Gaslighting refusal strip    │   │
│  │  • Panic recovery + cancel persist││
│  └─────────────────────────────────┘   │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │        Persistence              │   │
│  │  • SQLite sessions + memory DB  │   │
│  │  • Brain files (~/.opencrabs/)  │   │
│  │  • Hybrid FTS5 + vector search  │   │
│  └─────────────────────────────────┘   │
└─────────────────────────────────────────┘

Next Steps

Installation

Three ways to get OpenCrabs running.

Grab a pre-built binary from GitHub Releases.

Linux (amd64)

sudo apt install -y jq libgomp1
TAG=$(curl -s https://api.github.com/repos/adolfousier/opencrabs/releases/latest | jq -r .tag_name)
curl -fsSL "https://github.com/adolfousier/opencrabs/releases/download/${TAG}/opencrabs-${TAG}-linux-amd64.tar.gz" | tar xz
./opencrabs

Linux (arm64)

sudo apt install -y jq libgomp1
TAG=$(curl -s https://api.github.com/repos/adolfousier/opencrabs/releases/latest | jq -r .tag_name)
curl -fsSL "https://github.com/adolfousier/opencrabs/releases/download/${TAG}/opencrabs-${TAG}-linux-arm64.tar.gz" | tar xz
./opencrabs

macOS (arm64 / Apple Silicon)

TAG=$(curl -s https://api.github.com/repos/adolfousier/opencrabs/releases/latest | jq -r .tag_name)
curl -fsSL "https://github.com/adolfousier/opencrabs/releases/download/${TAG}/opencrabs-${TAG}-macos-arm64.tar.gz" | tar xz
./opencrabs

Windows

Download from GitHub Releases.

The onboarding wizard handles everything on first run.

Terminal permissions required. OpenCrabs reads/writes brain files, config, and project files. Your terminal app needs filesystem access or the OS will block operations.

OSWhat to do
macOSSystem Settings → Privacy & Security → Full Disk Access → toggle your terminal app ON (Alacritty, iTerm2, Terminal, etc.). If not listed, click “+” and add it from /Applications/. Without this, macOS repeatedly prompts “would like to access data from other apps”.
WindowsRun your terminal (Windows Terminal, PowerShell, cmd) as Administrator on first run, or grant the terminal write access to %USERPROFILE%\.opencrabs\ and your project directories. Windows Defender may also prompt — click “Allow”.
LinuxEnsure your user owns ~/.opencrabs/ and project directories. On SELinux/AppArmor systems, the terminal process needs read/write access to those paths. Flatpak/Snap terminals may need --filesystem=home or equivalent permission.

/rebuild works even with pre-built binaries — it auto-clones the source to ~/.opencrabs/source/ on first use, then builds and hot-restarts.

Option 2: Build from Source

Required for /rebuild, adding custom tools, or modifying the agent.

The setup script auto-detects your platform (macOS, Debian/Ubuntu, Fedora/RHEL, Arch) and installs all build dependencies + Rust:

# Install all dependencies
curl -fsSL https://raw.githubusercontent.com/adolfousier/opencrabs/main/scripts/setup.sh | bash

# Clone and build
git clone https://github.com/adolfousier/opencrabs.git
cd opencrabs
cargo build --release
./target/release/opencrabs

Manual setup

If you prefer to install dependencies yourself:

  • Rust stableInstall Rust. Stable toolchain works since v0.2.85
  • An API key from at least one supported provider
  • SQLite (bundled via rusqlite)
  • macOS: brew install cmake pkg-config
  • Debian/Ubuntu: sudo apt install build-essential pkg-config libssl-dev cmake
  • Fedora/RHEL: sudo dnf install gcc gcc-c++ make pkg-config openssl-devel cmake
  • Arch: sudo pacman -S base-devel pkg-config openssl cmake
git clone https://github.com/adolfousier/opencrabs.git
cd opencrabs
cargo build --release
./target/release/opencrabs

OpenCrabs uses keys.toml instead of .env for API keys. The onboarding wizard will help you set it up, or edit ~/.opencrabs/keys.toml directly.

Option 3: Docker

Run OpenCrabs in an isolated container. Build takes ~15min (Rust release + LTO).

git clone https://github.com/adolfousier/opencrabs.git
cd opencrabs
docker compose -f src/docker/compose.yml up --build

Config, workspace, and memory DB persist in a Docker volume across restarts. API keys in keys.toml are mounted into the container at runtime — never baked into the image.

Autostart on Boot

Keep OpenCrabs running as a background daemon that starts with your system.

Linux (systemd)

cat > ~/.config/systemd/user/opencrabs.service << 'EOF'
[Unit]
Description=OpenCrabs AI Agent
After=network.target

[Service]
ExecStart=%h/.cargo/bin/opencrabs daemon
Restart=on-failure
RestartSec=5
Environment=OPENCRABS_HOME=%h/.opencrabs

[Install]
WantedBy=default.target
EOF

systemctl --user daemon-reload
systemctl --user enable opencrabs
systemctl --user start opencrabs

Check status: systemctl --user status opencrabs | Logs: journalctl --user -u opencrabs -f

macOS (launchd)

cat > ~/Library/LaunchAgents/com.opencrabs.agent.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.opencrabs.agent</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/opencrabs</string>
        <string>daemon</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/tmp/opencrabs.log</string>
    <key>StandardErrorPath</key>
    <string>/tmp/opencrabs.err</string>
</dict>
</plist>
EOF

launchctl load ~/Library/LaunchAgents/com.opencrabs.agent.plist

Update the path in ProgramArguments to match your install location.

Windows (Task Scheduler)

  1. Win + Rtaskschd.msc
  2. Create Basic Task → Name: OpenCrabs
  3. Trigger: When I log on
  4. Action: Start a programC:\Users\<you>\.cargo\bin\opencrabs.exe, Arguments: daemon
  5. In Properties > Settings, check If the task fails, restart every 1 minute

Or via PowerShell:

$action = New-ScheduledTaskAction -Execute "$env:USERPROFILE\.cargo\bin\opencrabs.exe" -Argument "daemon"
$trigger = New-ScheduledTaskTrigger -AtLogon
$settings = New-ScheduledTaskSettingsSet -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
Register-ScheduledTask -TaskName "OpenCrabs" -Action $action -Trigger $trigger -Settings $settings

Updating

  • Binary users: Type /evolve in the TUI to download the latest release
  • Source users: git pull && cargo build --release, or type /rebuild in the TUI
  • Docker users: docker compose pull && docker compose up -d

Configuration

OpenCrabs uses two config files stored at ~/.opencrabs/:

FilePurpose
config.tomlProvider settings, features, channel connections
keys.tomlAPI keys and secrets (never committed to git)

Workspace Layout

~/.opencrabs/
├── config.toml          # Main configuration
├── keys.toml            # API keys (gitignored)
├── commands.toml        # Custom slash commands
├── opencrabs.db         # SQLite database
├── SOUL.md              # Agent personality
├── IDENTITY.md          # Agent identity
├── USER.md              # Your profile
├── MEMORY.md            # Long-term memory
├── AGENTS.md            # Agent behavior docs
├── TOOLS.md             # Tool reference
├── SECURITY.md          # Security policies
├── HEARTBEAT.md         # Periodic check tasks
├── memory/              # Daily memory notes
│   └── YYYY-MM-DD.md
├── images/              # Generated images
├── logs/                # Application logs
└── skills/              # Custom skills/plugins

Provider Configuration

See Provider Setup for detailed provider configuration.

Quick example — add Anthropic:

# config.toml
[providers.anthropic]
enabled = true
default_model = "claude-sonnet-4-20250514"
# keys.toml
[providers.anthropic]
api_key = "sk-ant-..."

Provider Priority

When multiple providers are enabled, the first one found in this order is used for new sessions:

MiniMax > OpenRouter > Anthropic > OpenAI > Gemini > Custom

Each session remembers which provider and model it was using. Switch providers per-session via /models.

Feature Flags

# config.toml
[agent]
working_directory = "/path/to/default/dir"
thinking = "on"                # "on", "off", or "budget_XXk"

[a2a]
enabled = false
bind = "127.0.0.1"
port = 18790

[image.generation]
enabled = true
model = "gemini-3.1-flash-image-preview"

[image.vision]
enabled = true
model = "gemini-3.1-flash-image-preview"

First Session

When you launch OpenCrabs for the first time, the onboarding wizard walks you through setup.

Onboarding Flow

  1. Provider selection — Choose your AI provider (Anthropic, OpenAI, Gemini, OpenRouter, or custom)
  2. API key — Enter your API key
  3. Model selection — Pick a default model (fetched live from the provider)
  4. Channel setup (optional) — Connect Telegram, Discord, Slack, or WhatsApp
  5. Image tools (optional) — Configure Gemini for image generation and vision

After onboarding, your agent boots up and introduces itself. It reads its brain files (SOUL.md, IDENTITY.md, AGENTS.md, TOOLS.md) and starts a conversation.

Bootstrap

On the very first run, the agent goes through a bootstrap phase:

  • Gets to know you (name, preferences, work style)
  • Establishes its identity (name, personality, emoji)
  • Opens SOUL.md together to discuss values
  • Sets up USER.md with your profile

The bootstrap file (BOOTSTRAP.md) deletes itself when complete.

Key Commands

CommandDescription
/helpShow all available commands
/modelsSwitch provider or model
/newCreate a new session
/sessionsSwitch between sessions
/cdChange working directory
/compactManually compact context
/evolveDownload latest version
/rebuildBuild from source
/approveSet approval policy

Approval Modes

Control how much autonomy the agent has:

ModeBehavior
/approveAsk before every tool use (default)
/approve autoAuto-approve for this session
/approve yoloAuto-approve always (persists)

Working Directory

The agent operates within a working directory for file operations. Change it with:

  • /cd command in chat
  • Directory picker in the TUI (Tab to select)
  • config_manager set_working_directory tool

The working directory is persisted per-session — switching sessions restores the directory automatically.

CLI Commands

OpenCrabs has a full CLI with 20+ subcommands for managing every aspect of the agent.

Usage

opencrabs [COMMAND] [OPTIONS]

Commands

CommandDescription
chat (default)Launch the TUI chat interface
daemonRun in background (channels only, no TUI)
agentInteractive multi-turn chat or single-message mode
cronManage scheduled tasks (add/list/remove/enable/disable/test)
channelChannel management (list, doctor)
memoryMemory management (list, get, stats)
sessionSession management (list, get)
dbDatabase management (init, stats, clear)
logsLog management (status, view, clean, open)
serviceSystem service management (install/start/stop/restart/status/uninstall)
statusShow agent status
doctorRun connection health check
onboardRun the setup wizard
completionsGenerate shell completions (bash/zsh/fish/powershell)
versionShow version info
!commandBang operator — Run any shell command instantly without an LLM round-trip. Output shown as system message. e.g. !git status, !ls -la
/evolveAuto-update — Downloads latest release and hot-restarts. Runs automatically on startup when [agent] auto_update = true

Configuration Flags

FlagDefaultDescription
[agent] auto_updatetrueAuto-install new releases on startup and hot-restart. Set to false to keep the manual prompt dialog.

Keyboard Shortcuts (TUI)

ShortcutAction
F12Toggle mouse capture on/off for native terminal text selection

Startup Update Prompt

When a new version is available, a centered dialog appears on the splash screen asking you to accept (Enter) or skip (Esc). Accepting triggers /evolve automatically. After update, the binary restarts and the splash shows the new version.

Channel Commands

/doctor, /help, /usage, /evolve, and system commands work directly on Telegram, Discord, Slack, and WhatsApp without going through the LLM. They execute instantly and return results in the channel.

All channel command logic is centralized in src/channels/commands.rs (847 lines) – a shared handler that eliminates duplicated command logic across 5 channel implementations. Each channel delegates to try_execute_text_command() for consistent behavior.

/evolve on channels now runs directly (downloads + installs the binary) without requiring an LLM round-trip. Previously it was routed through the agent.

Chat Mode

# Default — launch TUI
opencrabs

# Same as above
opencrabs chat

Agent Mode

Non-interactive mode for scripting and automation:

# Interactive multi-turn chat
opencrabs agent

# Single-message mode
opencrabs agent -m "What files changed today?"

Daemon Mode

Run OpenCrabs without the TUI — useful for servers where you only need channel bots. Supports a health endpoint for monitoring.

opencrabs daemon

The agent processes messages from all connected channels (Telegram, Discord, Slack, WhatsApp) but without the terminal UI. Channel bots auto-reconnect on network failures with 5-second backoff.

Health Endpoint

Add to config.toml to expose a health check:

[daemon]
health_port = 8080

Then GET http://localhost:8080/health returns 200 OK with JSON status. Useful for systemd watchdog, uptime monitors, or load balancers.

Service Management

Install OpenCrabs as a system service (launchd on macOS, systemd on Linux):

opencrabs service install
opencrabs service start
opencrabs service stop
opencrabs service restart
opencrabs service status
opencrabs service uninstall

Cron Management

# List all cron jobs
opencrabs cron list

# Add a new cron job
opencrabs cron add \
  --name "Daily Report" \
  --cron "0 9 * * *" \
  --tz "America/New_York" \
  --prompt "Check emails and summarize" \
  --provider anthropic \
  --model claude-sonnet-4-20250514 \
  --thinking off \
  --deliver-to telegram:123456

# Remove a cron job (accepts name or ID)
opencrabs cron remove "Daily Report"

# Enable/disable (accepts name or ID)
opencrabs cron enable "Daily Report"
opencrabs cron disable "Daily Report"

TUI Keyboard Shortcuts

KeyAction
EnterSend message
EscCancel / dismiss
Ctrl+NNew session
Ctrl+LSessions screen
Ctrl+KClear current session
Ctrl+OToggle tool group collapse
|Split pane horizontally
_Split pane vertically
Ctrl+XClose focused pane
TabCycle pane focus / Accept autocomplete
Up/DownNavigate suggestions / sessions
/Start slash command (e.g. /help, /models)
:Start emoji picker

Troubleshooting

Common issues and how to fix them.

Windows Defender Blocking OpenCrabs

Windows Defender may flag opencrabs.exe as suspicious because it’s an unsigned binary that executes shell commands and makes network requests. This is a false positive.

Add an exclusion:

  1. Open Windows SecurityVirus & threat protection
  2. Virus & threat protection settingsManage settings
  3. ExclusionsAdd or remove exclusions
  4. Add an exclusionFile → select opencrabs.exe

Or via PowerShell (admin):

Add-MpPreference -ExclusionPath "C:\path\to\opencrabs.exe"

If SmartScreen blocks the first run, click More infoRun anyway.


Binary Won’t Start or Crashes

Startup Errors

Run with debug logging to see what’s failing:

opencrabs -d chat

Logs are written to ~/.opencrabs/logs/.

Download a Previous Version

If the latest release crashes on your machine, download a previous working version from GitHub Releases:

# List all releases
gh release list -R adolfousier/opencrabs

# Download a specific version
gh release download v0.2.66 -R adolfousier/opencrabs -p "opencrabs-*$(uname -m)*$(uname -s | tr A-Z a-z)*"

/evolve — Update & Rollback

/evolve downloads the latest release from GitHub and hot-swaps the binary. It has built-in safety checks:

  1. Download — Fetches the platform-specific binary from GitHub Releases
  2. Pre-swap health check — Runs opencrabs health-check on the new binary (10s timeout). If it fails, the new binary is deleted and your current version stays untouched.
  3. Backup — Creates a backup at <binary-path>.evolve_backup
  4. Atomic swap — Replaces the current binary
  5. Post-swap health check — Verifies the swapped binary works. If it fails, auto-rolls back to the backup.
  6. Restart — exec()-restarts into the new version
  7. Brain update prompt — After restart, your crab announces the new version, diffs brain templates against your local files, and offers to update them

If /evolve Fails

The most common reason is the health check caught an issue — your current version stays safe. If something went wrong after the swap:

# Restore the backup manually
cp /path/to/opencrabs.evolve_backup /path/to/opencrabs
chmod +x /path/to/opencrabs

Cargo Install Fallback

When /evolve uses cargo install (building from source), it tries the stable toolchain first. If that fails, it automatically falls back to cargo +nightly. The progress message shows which toolchain succeeded.

Check-Only Mode

The agent can check for updates without installing:

/evolve check_only=true

Bash Tool Safety

The bash tool includes a hard command blocklist that prevents catastrophic commands even if accidentally approved:

  • rm -rf /, sudo rm -rf .
  • mkfs, dd to /dev/
  • Fork bombs
  • /etc overwrites, /proc writes
  • Sensitive file exfiltration
  • Crypto mining commands

These are blocked at the tool level — no configuration needed.


Older CPUs (Pre-2011 / No AVX)

Some features require AVX/AVX2 instructions. Since v0.2.67, OpenCrabs detects CPU capabilities at runtime and automatically hides unavailable options in the onboarding wizard.

What’s Affected

FeatureCPU RequirementFallback
Local embeddings (memory search)AVX (Sandy Bridge 2011+)FTS-only keyword search (still works)
Local STT (rwhisper/candle)AVX2 (Haswell 2013+)API mode (Groq Whisper) or disabled
Local TTS (Piper)None — tested on 2007 iMacWorks on any x86/ARM CPU

Symptoms

  • Local STT option doesn’t appear in /onboard:voice — your CPU lacks AVX2
  • Local TTS (Piper) should always be available — no CPU restrictions, works on machines as old as 2007
  • Memory search falls back to text-only FTS silently
  • Crash with “illegal instruction” on very old CPUs

Fix: Build from Source with CPU Targeting

# For your specific CPU (best performance)
RUSTFLAGS="-C target-cpu=native" cargo build --release

# For Sandy Bridge (AVX but no AVX2)
RUSTFLAGS="-C target-cpu=sandybridge" cargo build --release

macOS with Apple Silicon

Local STT uses Metal GPU acceleration on macOS — no CPU flags needed. Works out of the box on M1/M2/M3/M4.


Config Issues

Config Won’t Load

If config.toml has a syntax error, OpenCrabs will fail to start. Restore from backup:

# Check if a backup exists
ls ~/.opencrabs/config.toml.backup

# Restore it
cp ~/.opencrabs/config.toml.backup ~/.opencrabs/config.toml

Or reinitialize with defaults:

opencrabs init --force

Warning: --force overwrites your config. Back up keys.toml first — it contains your API keys.

Manual Backup

Always keep a backup of your critical files:

cp ~/.opencrabs/config.toml ~/.opencrabs/config.toml.backup
cp ~/.opencrabs/keys.toml ~/.opencrabs/keys.toml.backup
cp ~/.opencrabs/commands.toml ~/.opencrabs/commands.toml.backup

Channel Issues

Telegram

Bot not responding:

  1. Verify token from @BotFather is in keys.toml
  2. Check your numeric user ID is in allowed_users
  3. If respond_to = "mention", you must @mention the bot in groups

Regenerate bot token:

  1. Open @BotFather on Telegram
  2. /mybots → select bot → API Token → Revoke
  3. Copy new token to keys.toml under [channels.telegram]
  4. Restart OpenCrabs

Re-setup from scratch: Run /onboard:channels in the TUI.

WhatsApp

QR code / session expired:

WhatsApp sessions are stored at ~/.opencrabs/whatsapp/session.db. To reconnect:

# Delete the session file
rm ~/.opencrabs/whatsapp/session.db

# Re-pair via onboarding
opencrabs chat --onboard

Or press R on the WhatsApp onboarding screen to reset and get a fresh QR code.

Messages not received:

  • Verify phone number is in allowed_phones using E.164 format: "+15551234567"
  • Empty allowed_phones = [] means accept from everyone

Discord

Bot not receiving messages:

  1. Ensure Message Content Intent is enabled in Discord Developer Portal → Bot settings
  2. Required intents: gateway, guild_messages, direct_messages, message_content
  3. Use the bot token (starts with MTk...), not the application ID

Regenerate token: Discord Developer Portal → Bot → Regenerate Token

Slack

Both tokens required:

  • Bot token (xoxb-...): For sending messages
  • App token (xapp-...): For Socket Mode (receiving events)

Without the app token, the bot can send but not receive messages.

Socket Mode: Must be enabled in app settings → Features → Socket Mode → ON

Trello

Setup:

  1. Get API key: trello.com/app-key
  2. Generate token from the same page
  3. Add board_ids to config — the bot only monitors listed boards
  4. Set poll_interval_secs > 0 to enable polling (default 0 = disabled)

General: Re-run Channel Setup

For any channel issues, re-run the onboarding wizard:

opencrabs chat --onboard

Or type /onboard:channels in the TUI.


Local STT (Speech-to-Text)

Since v0.2.67, local STT uses rwhisper (candle, pure Rust) instead of whisper-rs/ggml. On macOS, it uses Metal GPU acceleration automatically.

Models

ModelSizeQuality
quantized-tiny~42 MBGood for short messages
base-en~142 MBBetter accuracy (English)
small-en~466 MBHigh accuracy
medium-en~1.5 GBBest accuracy

Models download automatically from HuggingFace on first use.

Common Issues

Local STT option not showing in wizard: Your CPU lacks AVX2. Use API mode (Groq Whisper) instead, or build from source with RUSTFLAGS="-C target-cpu=native".

“No audio samples decoded”: Audio file is corrupt or unsupported format. Supported: OGG/Opus, WAV.

Transcription hangs: Times out after 300 seconds. Try a smaller model (quantized-tiny).

Model download fails: Check network connection. Models are fetched from HuggingFace.

Audio too short: Messages under 1 second are automatically padded to prevent tensor errors.

Disabling

[voice]
stt_enabled = false

Local TTS (Text-to-Speech)

Requirements

  • Python 3 must be installed and in PATH
  • Piper installs automatically in a venv at ~/.opencrabs/models/piper/venv/

Voices

VoiceDescriptionSize
ryanUS Male (default)~200-400 MB
amyUS Female~200-400 MB
lessacUS Female~200-400 MB
kristinUS Female~200-400 MB
joeUS Male~200-400 MB
coriUK Female~200-400 MB

Common Issues

“python3 -m venv failed”: Install Python 3. On Ubuntu: sudo apt install python3 python3-venv. On macOS: brew install python3.

“pip install piper-tts failed”: Network issue or pip corrupted. Fix pip first:

python3 -m pip install --upgrade pip

Telegram voice messages show no waveform: This was fixed in v0.2.64 — audio is now properly encoded as OGG/Opus (RFC 7845). Update to latest version.

Voice preview not playing: Preview uses afplay (macOS), aplay (Linux), or powershell (Windows). Ensure audio output is available.

Re-setup

Run /onboard:voice in the TUI to reconfigure STT/TTS mode and re-download models.

Disabling

[voice]
tts_mode = "off"

The memory search engine uses a ~300 MB embedding model (llama.cpp) for semantic search. It requires AVX on x86 CPUs.

Fallback

If embeddings can’t initialize (no AVX, download failed, disk full), memory search falls back to FTS-only (keyword matching). It still works, just less semantic.

Fix for Older CPUs

Build from source with CPU targeting (see Older CPUs above).

Model Location

Models are stored in ~/.local/share/opencrabs/models/ (platform-specific data directory).


Database Issues

Location

  • Main database: ~/.opencrabs/opencrabs.db (SQLite + WAL)
  • WhatsApp session: ~/.opencrabs/whatsapp/session.db

Database Corruption

SQLite with WAL mode is very resilient, but if corruption occurs:

# Back up the corrupted file first
cp ~/.opencrabs/opencrabs.db ~/.opencrabs/opencrabs.db.corrupt

# Reinitialize (WARNING: loses all history)
opencrabs db init

Migration Errors

The database automatically migrates on startup (11 migrations). If migrating from an older version with sqlx, the transition is handled automatically — no manual steps needed.


Building from Source

Quick Setup

curl -fsSL https://raw.githubusercontent.com/adolfousier/opencrabs/main/scripts/setup.sh | bash
git clone https://github.com/adolfousier/opencrabs.git && cd opencrabs
cargo build --release

Build Without Voice (Smaller Binary)

cargo build --release --no-default-features --features telegram,whatsapp,discord,slack,trello

Feature Flags

FlagDefaultDescription
local-sttOnwhisper.cpp for local speech-to-text
local-ttsOnPiper for local text-to-speech
telegramOnTelegram channel
whatsappOnWhatsApp channel
discordOnDiscord channel
slackOnSlack channel
trelloOnTrello channel

Debug Mode

Run with -d for verbose logging:

opencrabs -d chat

Logs go to ~/.opencrabs/logs/ with 7-day retention.

Supported AI Providers

OpenCrabs supports 11+ AI providers out of the box. Switch between them at any time via /models in the TUI or any channel.

ProviderAuthModelsStreamingToolsNotes
Anthropic ClaudeAPI keyClaude Opus 4.6, Sonnet 4.5, Haiku 4.5YesYesExtended thinking, 200K context
OpenAIAPI keyGPT-5 Turbo, GPT-5, o3/o4-miniYesYesModels fetched live
GitHub CopilotOAuthGPT-4o, Claude Sonnet 4+YesYesUses your Copilot subscription — no API charges
OpenRouterAPI key400+ modelsYesYesFree models available. Reasoning output support (Qwen 3.6 Plus, etc.)
Google GeminiAPI keyGemini 2.5 Flash, 2.0, 1.5 ProYesYes1M+ context, vision, image generation
MiniMaxAPI keyM2.7, M2.5, M2.1, Text-01YesYesCompetitive pricing, auto-configured vision
z.ai GLMAPI keyGLM-4.5 through GLM-5 TurboYesYesGeneral API + Coding API endpoints
Claude CLICLI authVia claude binaryYesYesUses your Claude Code subscription
Qwen/DashScopeAPI keyqwen3.6-plus (default)YesYesDashScope API-key provider (replaced OAuth rotation). Local model tool-call extraction from text (bare JSON, Claude-style XML, Qwen formats). Prompt caching via cache_control, rate limit retry with exponential backoff
OpenCode CLINoneFree models (Mimo, etc.)YesYesFree — no API key or subscription needed
CustomOptionalAnyYesYesOllama, LM Studio, Groq, NVIDIA, any OpenAI-compatible API

How It Works

  • One provider active at a time per session — switch with /models
  • Per-session isolation — each session remembers its own provider and model. Changing provider in the TUI does not affect other active sessions (Telegram, Discord, Slack)
  • Fallback chain — configure automatic failover when the primary provider goes down
  • Models fetched live — no binary update needed when providers add new models
  • Function calling detection — OpenCrabs detects when a model doesn’t support tool use and warns you with a model switch suggestion, rather than silently failing
  • tool_choice: "auto" — sent automatically for OpenAI-compatible providers when tools are active, enabling function calling on models that require explicit opt-in

OpenRouter Reasoning

For models that support extended reasoning (e.g. Qwen 3.6 Plus), OpenCrabs sends include_reasoning: true automatically when using OpenRouter. Thinking/reasoning output is displayed in collapsible sections:

▶ Thinking... (click to expand)
  The user wants to refactor...

Reasoning text wraps to screen width instead of truncating.

See Provider Setup for configuration details and API key setup.

AI Provider Setup

OpenCrabs supports multiple AI providers. Configure them in config.toml and keys.toml at ~/.opencrabs/.

Anthropic Claude

Models: claude-opus-4-6, claude-sonnet-4-5, claude-haiku-4-5, and legacy models — fetched live from the API.

# keys.toml
[providers.anthropic]
api_key = "sk-ant-..."
# config.toml
[providers.anthropic]
enabled = true
default_model = "claude-sonnet-4-20250514"

Features: Streaming, tool use, extended thinking, vision, 200K context window.

OpenAI

Models: GPT-5 Turbo, GPT-5, and others — fetched live.

# keys.toml
[providers.openai]
api_key = "sk-YOUR_KEY"

OpenRouter — 400+ Models

Access 400+ models from every major provider through a single API key. Includes free models (DeepSeek-R1, Llama 3.3, Gemma 2, Mistral 7B).

# keys.toml
[providers.openrouter]
api_key = "sk-or-YOUR_KEY"

Get a key at openrouter.ai/keys. Model list is fetched live — no binary update needed when new models are added.

Google Gemini

Models: gemini-2.5-flash, gemini-2.0-flash, gemini-1.5-pro — fetched live.

# keys.toml
[providers.gemini]
api_key = "AIza..."
# config.toml
[providers.gemini]
enabled = true
default_model = "gemini-2.5-flash"

Features: Streaming, tool use, vision, 1M+ token context window.

Gemini also powers the separate image generation and vision tools. See Image Generation & Vision.

GitHub Copilot

Use your existing GitHub Copilot subscription — no separate API charges. Authenticates via OAuth device flow.

# config.toml
[providers.github_copilot]
enabled = true

Setup: Run /onboard:providers → select GitHub Copilot → follow the device code flow at github.com/login/device. Models are fetched live from the Copilot API.

Requirements: An active GitHub Copilot subscription (Individual, Business, or Enterprise).

z.ai (Zhipu AI)

Models: GLM-4-Plus, GLM-4-Flash, GLM-4-0520, CodeGeeX — fetched live. Two endpoint types: General API and Coding API.

# keys.toml
[providers.zai]
api_key = "your-api-key"
# config.toml
[providers.zai]
enabled = true
default_model = "glm-4-plus"

Get your API key at open.bigmodel.cn.

Claude CLI

Use your existing Claude Code subscription through the local claude binary — no separate API key needed. Supports streaming and extended thinking.

# config.toml
[providers.claude_cli]
enabled = true

Requirements: The claude CLI must be installed and authenticated. Models are detected automatically.

OpenCode CLI

Use the local opencode binary for free LLM completions — no API key or subscription needed. Supports NDJSON streaming and extended thinking.

# config.toml
[providers.opencode_cli]
enabled = true

Requirements: The opencode binary must be installed and available in your PATH. Models are fetched live via opencode models.

MiniMax

Models: MiniMax-M2.7, MiniMax-M2.5, MiniMax-M2.1, MiniMax-Text-01

# keys.toml
[providers.minimax]
api_key = "your-api-key"

Get your API key from platform.minimax.io. Model list comes from config.toml (no /models endpoint).

Custom (OpenAI-Compatible)

Use for Ollama, LM Studio, LocalAI, Groq, or any OpenAI-compatible API.

# config.toml
[providers.custom.lm_studio]
enabled = true
base_url = "http://localhost:1234/v1"
default_model = "qwen2.5-coder-7b-instruct"
models = ["qwen2.5-coder-7b-instruct", "llama-3-8B"]

Local LLMs: No API key needed — just set base_url and default_model.

Remote APIs (Groq, etc.): Add the key in keys.toml:

[providers.custom.groq]
api_key = "your-api-key"

Multiple Custom Providers

Define as many as you need with different names:

[providers.custom.lm_studio]
enabled = true
base_url = "http://localhost:1234/v1"
default_model = "qwen2.5-coder-7b-instruct"

[providers.custom.ollama]
enabled = false
base_url = "http://localhost:11434/v1"
default_model = "mistral"

Free Prototyping with NVIDIA API

Kimi K2.5 is available for free on the NVIDIA API Catalog — no billing required.

# config.toml
[providers.custom.nvidia]
enabled = true
base_url = "https://integrate.api.nvidia.com/v1"
default_model = "moonshotai/kimi-k2.5"
# keys.toml
[providers.custom.nvidia]
api_key = "nvapi-..."

Fallback Provider Chain

Configure automatic failover when the primary provider fails (rate limits, outages, errors). Fallbacks are tried in order until one succeeds.

# config.toml
[providers.fallback]
enabled = true
providers = ["openrouter", "anthropic"]  # Tried in order on failure

Each fallback provider must have its API key configured in keys.toml. Both complete() and stream() calls are retried transparently — no changes needed downstream.

Single fallback shorthand:

[providers.fallback]
enabled = true
provider = "openrouter"

Or just ask your Crab: “Set up fallback providers using openrouter and anthropic” — it will configure config.toml for you at runtime.

Vision Model

When your default chat model doesn’t support vision, set vision_model to a vision-capable model on the same provider. This registers a vision tool that the agent can call — it sends the image to the vision model, gets a description back, and the chat model uses that context to reply.

# config.toml
[providers.minimax]
enabled = true
default_model = "MiniMax-M2.5"
vision_model = "MiniMax-Text-01"  # Agent calls vision tool → this model describes image → M2.5 replies
[providers.openai]
enabled = true
default_model = "gpt-5-nano"
vision_model = "gpt-5-nano"

MiniMax auto-configures vision_model = "MiniMax-Text-01" on first run. You can also ask your Crab to set it up: “Configure vision model for MiniMax” — it will update config.toml at runtime.

This is separate from the Gemini image tools which provide dedicated generate_image and analyze_image tools.

Per-Session Providers

Each session remembers its provider and model. Switch to Claude in one session, Gemini in another — switching sessions restores the provider automatically.

Image Generation & Vision

OpenCrabs supports image generation and vision analysis via Google Gemini. These features are independent of the main chat provider — use Claude for chat and Gemini for images.

Setup

  1. Get a free API key from aistudio.google.com
  2. Run /onboard:image in chat to configure interactively
  3. Or add manually:
# keys.toml
[image]
api_key = "AIza..."
# config.toml
[image.generation]
enabled = true
model = "gemini-3.1-flash-image-preview"

[image.vision]
enabled = true
model = "gemini-3.1-flash-image-preview"

Agent Tools

When enabled, two tools become available automatically:

ToolDescription
generate_imageGenerate an image from a text prompt — saves to ~/.opencrabs/images/
analyze_imageAnalyze an image file or URL via Gemini vision

Example prompts:

  • “Generate a pixel art crab logo” — agent calls generate_image, returns file path
  • “What’s in this image: /tmp/screenshot.png” — agent calls analyze_image via Gemini

Incoming Images

When a user sends an image from any channel, it arrives as <<IMG:/tmp/path>> in the message. The file is already downloaded — the agent can:

  • See it directly (if the model supports vision)
  • Pass the path to analyze_image for Gemini analysis
  • Use the path in bash commands or any tool that accepts file paths
  • Reference it in replies with <<IMG:path>> to forward to channels

Model

Both tools use gemini-3.1-flash-image-preview — Gemini’s dedicated image model that supports both vision input and image output in a single request.

Per-Provider Vision Model

Separately from the Gemini analyze_image tool, any provider can have its own vision tool via vision_model. When the user sends an image and the chat model can’t handle it natively, the agent calls the provider’s vision tool — which sends the image to the vision_model on the same provider, gets a text description back, and uses that context to reply.

Example: User sends an image to MiniMax M2.5 (no native vision). The agent calls the vision tool, which sends the image to MiniMax-Text-01, gets the description, and M2.5 replies using that context.

See Provider Setup — Vision Model.

Channel Integrations

OpenCrabs connects to multiple messaging platforms simultaneously. All channels share the TUI session by default, with per-user sessions for non-owners.

Supported Channels

ChannelProtocolImages InVoice InImage Gen OutSetup
TelegramLong pollingVision pipelineSTTNative photoBot token
DiscordWebSocketVision pipelineSTTFile attachmentBot token
SlackSocket ModeVision pipelineSTTFile uploadBot + App token
WhatsAppQR pairingVision pipelineSTTNative imageQR code
TrelloREST APICard attachmentsCard attachmentAPI key + token

Common Features

All messaging channels support:

  • Shared session with TUI (owner) or per-user sessions (non-owners)
  • Slash commands/help, /models, /new, /sessions, custom commands
  • Inline buttons — Provider picker, model picker, session switcher (Telegram, Discord, Slack)
  • User allowlists — Restrict access by user ID, chat ID, or phone number
  • respond_to filterall, dm_only, or mention (respond only when @mentioned)

File & Media Support

ChannelImages (in)Text files (in)Documents (in)Audio (in)Image gen (out)
TelegramVision pipelineExtracted inlinePDF noteSTTNative photo
WhatsAppVision pipelineExtracted inlinePDF noteSTTNative image
DiscordVision pipelineExtracted inlinePDF noteSTTFile attachment
SlackVision pipelineExtracted inlinePDF noteSTTFile upload
TrelloCard attachments → visionExtracted inlineCard attachment
TUIPaste path → visionPaste path → inlineSTT[IMG: name] display

Images are passed to the active model’s vision pipeline if it supports multimodal input, or routed to the analyze_image tool (Google Gemini vision) otherwise. Text files are extracted as UTF-8 and included inline up to 8,000 characters.

Proactive Channel Tools

The agent can send messages and take actions proactively:

ToolActions
discord_send17 actions: send, reply, react, edit, delete, pin, create_thread, send_embed, etc.
slack_send17 actions: send, reply, react, edit, delete, pin, set_topic, send_blocks, etc.
trello_send22 actions: create_card, move_card, add_comment, add_checklist, search, etc.

Telegram

Connect OpenCrabs to Telegram for DMs and group chats.

Setup

  1. Message @BotFather on Telegram
  2. Create a new bot with /newbot
  3. Copy the bot token
  4. Add to keys.toml:
[channels.telegram]
bot_token = "123456:ABC..."
  1. Enable in config.toml:
[channels.telegram]
enabled = true
owner_chat_id = 123456789  # Your Telegram user ID

Get your chat ID by messaging @userinfobot on Telegram.

Features

  • DMs and groups — Works in private chats and group conversations
  • Inline buttons — Provider picker, model picker, session switcher use Telegram inline keyboards
  • Image support — Send images to the bot, receive generated images
  • Voice messages — STT transcription + TTS response
  • All slash commands/help, /models, /new, /sessions, custom commands
  • Owner vs non-owner — Owner uses the shared TUI session, non-owners get per-user sessions

Agent Tools

The agent can use telegram_send with 19 actions:

ActionDescription
send_messageSend text message
send_imageSend image file
send_documentSend document
send_voiceSend voice message
get_updatesGet recent messages
pin_messagePin a message
And more…

Group Chat Behavior

In groups, the agent:

  • Responds when mentioned by name or replied to
  • Stays quiet when the conversation doesn’t involve it
  • Tracks context from group messages passively

Discord

Connect OpenCrabs to Discord for server and DM interactions.

Setup

  1. Go to discord.com/developers/applications
  2. Create a new application
  3. Go to Bot section, create a bot
  4. Enable MESSAGE CONTENT Intent (required)
  5. Copy the bot token
  6. Add to keys.toml:
[channels.discord]
bot_token = "your-bot-token"
  1. Enable in config.toml:
[channels.discord]
enabled = true
  1. Invite the bot to your server using the OAuth2 URL with bot scope and Send Messages, Read Message History permissions

Features

  • Server channels and DMs — Works in text channels and direct messages
  • Button interactions — Provider picker, model picker, session switcher use Discord buttons
  • Image support — Send and receive images
  • Embed suppression — Agent wraps multiple links in <> to suppress embeds
  • Slash commands — All built-in and custom commands work
  • Reactions — Agent can add emoji reactions to messages

Formatting Notes

  • No markdown tables in Discord — use bullet lists instead
  • Wrap multiple links in <url> to suppress embeds

Slack

Connect OpenCrabs to Slack workspaces.

Setup

  1. Go to api.slack.com/apps
  2. Create a new app
  3. Enable Socket Mode
  4. Add bot scopes: chat:write, channels:history, groups:history, im:history, reactions:write
  5. Install to workspace
  6. Copy the Bot Token and App-Level Token
  7. Add to keys.toml:
[channels.slack]
bot_token = "xoxb-..."
app_token = "xapp-..."
  1. Enable in config.toml:
[channels.slack]
enabled = true

Features

  • Channels and DMs — Works in public/private channels and direct messages
  • Action buttons — Provider picker, model picker, session switcher use Slack action buttons
  • Thread support — Responds in threads when appropriate
  • Slash commands — All built-in and custom commands work
  • Reactions — Agent can add emoji reactions

Socket Mode

Slack uses Socket Mode (WebSocket) instead of HTTP webhooks — no public URL or ngrok needed. The connection is outbound from your machine.

WhatsApp

Connect OpenCrabs to WhatsApp via QR code pairing.

Setup

  1. Enable in config.toml:
[channels.whatsapp]
enabled = true
  1. On first run, a QR code appears in the terminal
  2. Open WhatsApp on your phone → Settings → Linked Devices → Link a Device
  3. Scan the QR code

The session persists across restarts — no need to re-scan.

Features

  • Personal and group chats — Works in DMs and group conversations
  • Image support — Send and receive images
  • Voice messages — STT transcription + TTS response
  • Plain text UI — No buttons (WhatsApp limitation), uses text-based menus
  • Slash commands — All built-in and custom commands work

Formatting Notes

  • No markdown tables — use bullet lists
  • No headers — use bold or CAPS for emphasis
  • Links render natively

Voice Message Handling

When receiving a voice message:

  1. Agent downloads and transcribes via STT
  2. Sends text response first (searchable)
  3. Optionally generates TTS audio response

Trello

OpenCrabs integrates with Trello for board and card management via the trello_send tool.

Setup

  1. Get an API Key and Token from trello.com/power-ups/admin
  2. Configure in keys.toml:
# keys.toml
[channels.trello]
api_key = "your-api-key"
token = "your-token"
  1. Configure boards and access:
# config.toml
[channels.trello]
enabled = true
boards = ["Board Name or ID"]
member_id = "your-member-id"
# poll_interval_secs = 300  # Optional: poll for @mentions

Tool Actions

The trello_send tool supports 22 actions:

ActionDescription
create_cardCreate a new card
get_cardGet card details
update_cardUpdate card fields
move_cardMove card to another list
archive_cardArchive a card
find_cardsSearch for cards
add_commentAdd a comment to a card
get_card_commentsRead card comments
add_checklistAdd a checklist to a card
add_checklist_itemAdd an item to a checklist
complete_checklist_itemMark checklist item done
add_label_to_cardAdd a label
remove_label_from_cardRemove a label
add_member_to_cardAssign a member
remove_member_from_cardUnassign a member
add_attachmentAttach a file or URL
list_boardsList accessible boards
list_listsList columns in a board
get_board_membersGet board members
searchSearch across boards
get_notificationsGet notifications
mark_notifications_readMark notifications read

Behavior

  • Tool-only by default — The agent acts on Trello only when explicitly asked
  • Optional polling — Set poll_interval_secs to enable monitoring for @bot_username mentions
  • Image attachments — Generated images are sent as card attachments with embedded previews
  • File attachments — Card attachments (images, documents) are fetched and processed through the vision pipeline

Built-in Tools

OpenCrabs ships with 50+ tools available to the agent out of the box, plus support for user-defined dynamic tools.

File Operations

ToolParametersDescription
lspathList directory contents
globpattern, pathFind files by glob pattern
greppattern, path, includeSearch file contents with regex
read_filepath, line_start, line_endRead file contents
edit_filepath, old_string, new_stringEdit files with search/replace
write_filepath, contentWrite new files

Code Execution

ToolParametersDescription
bashcommand, timeoutExecute shell commands
execute_codelanguage, codeRun code in sandboxed environment

Web & Network

ToolParametersDescription
web_searchquerySearch the web (Brave Search)
http_requestmethod, url, headers, bodyMake HTTP requests

Session & Memory

ToolParametersDescription
session_searchquery, limitSemantic search across sessions
session_contextactionRead/write session context
task_manageraction, variousManage plans and tasks

Image

ToolParametersDescription
generate_imageprompt, filenameGenerate images via Gemini
analyze_imageimage, questionAnalyze images via Gemini vision

Channel Integrations

ToolParametersDescription
telegram_sendaction, variousTelegram operations (19 actions)
discord_connectaction, variousDiscord operations (17 actions)
slack_sendaction, variousSlack operations (17 actions)
trello_connectaction, variousTrello operations (22 actions)

Sub-Agent Orchestration

Agents can spawn independent child agents for parallel task execution:

ToolParametersDescription
spawn_agentlabel, agent_type, promptSpawn a typed child agent in an isolated session
wait_agentagent_id, timeout_secsWait for a child agent to complete and return output
send_inputagent_id, textSend follow-up input to a running agent (multi-turn)
close_agentagent_idTerminate a running agent and clean up resources
resume_agentagent_id, promptResume a completed/failed agent with new prompt (preserves context)
team_createteam_name, agents[]Spawn N typed agents as a named team (parallel)
team_broadcastteam_name, messageFan-out message to all running agents in a team
team_deleteteam_nameCancel and clean up all agents in a team

Agent Types

When spawning, agent_type selects a specialized role with a curated tool registry:

TypeRoleTool Access
generalFull-capability (default)All parent tools minus recursive/dangerous
exploreFast read-only codebase navigationread_file, glob, grep, ls
planArchitecture planningread_file, glob, grep, ls, bash
codeImplementation with full write accessAll parent tools minus recursive/dangerous
researchWeb search + documentation lookupread_file, glob, grep, ls, web_search, http_request

ALWAYS_EXCLUDED tools (no agent type has these): spawn_agent, resume_agent, wait_agent, send_input, close_agent, rebuild, evolve – no recursive spawning, no self-modification from subagents.

Browser Automation

Native headless Chrome control via Chrome DevTools Protocol (CDP):

ToolParametersDescription
navigateurlOpen a URL in the browser
clickselectorClick an element by CSS selector
typeselector, textType text into an input field
screenshotselectorCapture a screenshot
eval_jscodeExecute JavaScript in the page context
extract_contentselectorExtract text content from elements
wait_for_elementselector, timeoutWait for an element to appear

Auto-detects your default Chromium browser. Feature-gated under browser (enabled by default).

Dynamic Tools

Define custom tools at runtime via ~/.opencrabs/tools.toml. See Dynamic Tools for details.

ToolParametersDescription
tool_manageaction, variousCreate, remove, or reload dynamic tools

System

ToolParametersDescription
slash_commandcommand, argsExecute slash commands (/cd, /compact, etc.)
config_manageraction, variousRead/write config, manage commands
evolvecheck_onlyDownload latest release
rebuildBuild from source and restart
planaction, variousCreate and manage execution plans

Error Handling

v0.2.92 improved error surfacing across all tool connections. Channel connect tools (slack_connect, whatsapp_connect, trello_connect) now surface actual connection errors instead of silently swallowing them. Tool call status correctly transitions from “running” to success/failure instead of showing a perpetual spinner.

System CLI Tools

OpenCrabs runs in a TUI with full terminal access. The agent can execute any CLI tool installed on the host via the bash tool – no plugins, no wrappers. If it’s on your system, the agent can use it. Common ones:

ToolPurposeCheck
ghGitHub CLI — issues, PRs, repos, releases, actionsgh --version
gogGoogle CLI — Gmail, Calendar (OAuth)gog --version
dockerContainer managementdocker --version
sshRemote server accessssh -V
nodeRun JavaScript/TypeScript toolsnode --version
python3Run Python scripts and toolspython3 --version
ffmpegAudio/video processingffmpeg -version
curlHTTP requests (fallback when http_request insufficient)curl --version

GitHub CLI (gh)

Authenticated GitHub CLI for full repo management:

gh issue list / view / create / close / comment
gh pr list / view / create / merge / checks
gh release list / create
gh run list / view / watch

Google CLI (gog)

OAuth-authenticated Google Workspace CLI. Supports Gmail and Calendar:

gog calendar events --max 10
gog gmail search "is:unread" --max 20
gog gmail send --to user@email.com --subject "Subject" --body "Body"

Requires GOG_KEYRING_PASSWORD and GOG_ACCOUNT env vars.

Companion Tools

SocialCrabs — Social Media Automation

SocialCrabs is a social media automation tool with human-like behavior simulation (Playwright). Supports Twitter/X, Instagram, and LinkedIn.

The agent calls SocialCrabs CLI commands via bash:

node dist/cli.js x tweet "Hello world"
node dist/cli.js x mentions -n 5
node dist/cli.js ig like <post-url>
node dist/cli.js linkedin connect <profile-url>

Read operations are safe. Write operations (tweet, like, follow, comment) require explicit user approval.

WhisperCrabs — Floating Voice-to-Text

WhisperCrabs is a floating voice-to-text widget controllable via D-Bus. Click to record, click to stop, text goes to clipboard. The agent can start/stop recording, switch providers, and view transcription history via D-Bus commands.

Custom Commands

Define your own slash commands in ~/.opencrabs/commands.toml. Commands work from the TUI and all channels (Telegram, Discord, Slack, WhatsApp).

Configuration

# ~/.opencrabs/commands.toml

[commands.credits]
description = "Show remaining API credits"
action = "prompt"
value = "Check my API credit balance across all providers and give me a summary"

[commands.deploy]
description = "Deploy to production"
action = "prompt"
value = "Run the production deployment pipeline: git pull, build, test, deploy"

[commands.status]
description = "Show system status"
action = "system"
value = "System is operational. All channels connected."

Action Types

ActionBehavior
promptSends the value as a message to the agent — the agent processes it like any user message
systemDisplays the value directly as a system message — no agent involvement

Using Commands

Type /commandname in the TUI or any connected channel:

/credits     → agent checks API balances
/deploy      → agent runs deployment
/status      → shows static system message

Visibility

Custom commands appear in:

  • /help output (TUI and channels) under a “Custom Commands” section
  • TUI slash autocomplete when typing /

Commands are sorted alphabetically and show their description.

Memory System

OpenCrabs uses a 3-tier memory system for persistent context across sessions.

Memory Tiers

1. Daily Notes (memory/YYYY-MM-DD.md)

Automatic daily files for session-specific observations:

~/.opencrabs/memory/2026-03-07.md

The agent writes here during conversations — new integrations, bugs fixed, decisions made, server changes.

2. Long-term Memory (MEMORY.md)

Curated knowledge that persists across all sessions:

  • Server details, SSH access, credentials locations
  • User preferences and workflows
  • Integration configurations
  • Lessons learned from debugging

Full-text search across all past sessions stored in SQLite. The agent can query:

  • Previous conversations
  • Tool execution history
  • Past decisions and context

The agent uses session_search for fast memory lookups (~500 tokens) instead of reading full memory files (~15K tokens). This is the primary recall mechanism.

Context Compaction

When context reaches ~80% capacity, OpenCrabs automatically compacts:

  1. Summarizes the conversation so far into a comprehensive continuation document
  2. Clears old messages from context
  3. Continues with the summary as context

Manual compaction: type /compact in chat.

Auto-Save Triggers

The agent saves to memory when:

  • New integrations are connected
  • Server/infrastructure changes occur
  • Bugs are found and fixed
  • New tools are configured
  • Credentials are rotated
  • Architecture decisions are made
  • You say “remember this”
  • Errors take >5 minutes to debug

Brain Files

See Brain Files for the full list of files the agent reads on startup.

Brain Files

Brain files define the agent’s personality, knowledge, and behavior. They live at ~/.opencrabs/ and are loaded on every session start.

Startup Read Order

  1. SOUL.md — Personality and values
  2. USER.md — Your profile and preferences
  3. memory/YYYY-MM-DD.md — Today’s notes
  4. MEMORY.md — Long-term memory
  5. AGENTS.md — Agent behavior guidelines
  6. TOOLS.md — Tool reference and custom notes
  7. CODE.md — Coding standards and file organization
  8. SECURITY.md — Security policies
  9. HEARTBEAT.md — Periodic check tasks

File Reference

SOUL.md

Agent personality. Core truths: strong opinions, brevity, resourcefulness, honesty. Hard rules: never delete files without approval, never send emails without request, never commit code directly.

IDENTITY.md

Agent identity created during bootstrap: name, creature type, vibe, emoji, prohibited patterns.

USER.md

Your profile: name, location, timezone, role, specialties, communication preferences, pet peeves.

AGENTS.md

Comprehensive agent behavior docs: memory system, safety rules, git rules, workspace vs repository separation, cron best practices, platform formatting, heartbeat guidelines.

TOOLS.md

Tool parameter reference, system CLI tools, provider configuration, integration details for all channels and services.

CODE.md

Coding standards brain template. Enforces: no file over 500 lines (target 100–250), types in types.rs, one responsibility per file, mandatory tests for every feature, security-first patterns. Rust-first philosophy — single binary, no runtime dependencies. The agent follows these rules when writing or reviewing code.

SECURITY.md

Security policies: third-party code review, attack playbook awareness, network security, data handling, incident response.

HEARTBEAT.md

Tasks for periodic proactive checks. Keep empty to skip heartbeat API calls. Add tasks for the agent to rotate through (email checks, calendar, weather, etc.).

BOOT.md

Startup procedures: check git log, verify build, greet human with context awareness.

Customization

These files are yours. The agent reads them but you control the content. Templates are at src/docs/reference/templates/ in the source repo — compare your local files against templates when updating to pick up new sections without losing custom content.

New installs (v0.2.72+): CODE.md and SECURITY.md are automatically seeded on first run. Existing users can ask their crab: “Check my brain templates and update them if any are missing or outdated.”

Upgrading: Brain files are never overwritten by /evolve or /rebuild. After updating, ask your crab to compare templates against local files and patch in new sections.

Sessions

OpenCrabs supports multiple concurrent sessions, each with its own conversation history, provider, model, and working directory.

Creating Sessions

  • TUI: Press Ctrl+N or type /new
  • Channels: Type /new in any channel

Switching Sessions

  • TUI: Press Ctrl+L to open the sessions screen, navigate with arrow keys, press Enter to select
  • Channels: Type /sessions to see recent sessions with inline buttons

Session Screen

The sessions screen shows:

  • Session name
  • Created date
  • Provider/model badge
  • Working directory
  • Token usage
  • Context window usage (current session)
  • Status indicators (processing spinner, pending approval, unread)

Per-Session State

Each session remembers:

  • Provider and model — Switch to Claude in one, Gemini in another
  • Working directory/cd persists per session
  • Conversation history — Full message history in SQLite
  • Token count and cost — Cumulative usage tracking

Session Management

ActionTUIChannels
NewCtrl+N / /new/new
SwitchCtrl+L + Enter/sessions
RenameR on sessions screen
DeleteD on sessions screen

Background Processing

Sessions can process in the background while you work in another session. The sessions screen shows:

  • Spinner for actively processing sessions
  • ! for sessions waiting for tool approval
  • Dot for sessions with unread messages

Split Panes

Run multiple sessions side by side with tmux-style pane splitting. See Split Panes for details.

State Management

v0.2.92 improved session state tracking:

  • Session reload after cancellation – After Esc+Esc cancel, session context reloads from DB to pick up any changes made during the cancelled operation
  • Cached state cleanup – Deleting a session now clears stale pane cache entries, preventing phantom state on restart
  • CLI tool segment persistence – Tool results from CLI providers (Claude CLI, OpenCode CLI) are now saved to DB alongside regular messages, preserving correct text/tool interleaving across restarts
  • Case-insensitive tool input – Tool input descriptions use case-insensitive key lookup, fixing failures when providers return different casing

Channel Sessions

All channels (Telegram, Discord, Slack, WhatsApp, Trello) now persist sessions in SQLite by channel/group title. Sessions survive process restarts – no more lost context after daemon restart. Each channel group gets its own isolated session, while owner DMs share the TUI session.

Split Panes

OpenCrabs supports tmux-style pane splitting in the TUI. Run multiple sessions side by side, each with its own provider, model, and context — all processing in parallel.

Splitting

ActionShortcut
Split horizontal| (pipe)
Split vertical_ (underscore)
Cycle focusTab
Close paneCtrl+X

How It Works

Each pane runs an independent session. You can have one pane writing code with Claude while another reviews tests with Gemini. The status bar shows [n/total] to indicate which pane is focused.

  • Independent providers — Each pane can use a different AI provider and model
  • Independent context — Conversation history is isolated per pane
  • Parallel processing — All panes process concurrently via Tokio
  • Persistent sessions — Each pane’s session is saved to SQLite like any other session

Example Layout

┌──────────────────────┬──────────────────────┐
│  Session 1 (Claude)  │  Session 2 (Gemini)  │
│  Writing code...     │  Reviewing PR...     │
├──────────────────────┴──────────────────────┤
│  Session 3 (OpenRouter)                      │
│  Running tests...                            │
└──────────────────────────────────────────────┘

Split vertically with _, then horizontally with | in the top pane.

Persistent Layout

Split pane configuration (splits, sizes, focused pane) saves to ~/.opencrabs/pane_layout.json on quit and Ctrl+C. On restart, your layout is restored exactly as you left it. Each restored pane preloads its session messages from the database, so content is visible immediately instead of blank.

Non-Focused Panes

Non-focused panes show compact tool call summaries and stripped reasoning text. Tool groups display as single collapsed lines matching the focused pane style. All panes auto-scroll to the bottom when new messages arrive.

v0.2.92 fixed several rendering issues:

  • Tool calls no longer show a perpetual “running” spinner after completion
  • Scroll position correctly tracks for inactive panes
  • Stale cache is cleared when sessions are updated or deleted

State Management

Deleting a session now properly cleans up cached pane state. Previously, deleting a session left stale entries in the pane cache, which could cause phantom panes on restart.

Limits

There is no hard limit on pane count – you can run as many as your terminal fits. Each pane is a full session with its own token tracking and working directory.

Dynamic Tools

Define custom tools at runtime without recompiling. Tools are defined in ~/.opencrabs/tools.toml and can be created, removed, and reloaded on the fly.

Defining Tools

Create ~/.opencrabs/tools.toml:

[[tools]]
name = "deploy"
description = "Deploy the application to production"
executor = "shell"
command = "cd {{project_dir}} && ./deploy.sh {{environment}}"

[[tools]]
name = "check-status"
description = "Check service health"
executor = "http"
method = "GET"
url = "https://api.example.com/health"

Executors

ExecutorDescription
shellRuns a shell command
httpMakes an HTTP request

Template Parameters

Use {{param}} syntax for dynamic values. The agent fills these in when calling the tool:

[[tools]]
name = "search-logs"
description = "Search application logs for a pattern"
executor = "shell"
command = "grep -r '{{pattern}}' /var/log/myapp/ --include='*.log' -l"

Runtime Management

The tool_manage meta-tool lets the agent manage dynamic tools during a session:

  • Create — Add a new tool definition
  • Remove — Delete an existing dynamic tool
  • Reload — Re-read tools.toml without restarting

Dynamic tools appear alongside built-in tools in the agent’s tool list. Enable or disable individual tools without restarting the process.

Browser Automation

OpenCrabs includes native headless Chrome control via the Chrome DevTools Protocol (CDP). No Selenium, no Playwright — direct browser control built into the binary.

Requirements

  • A Chromium-based browser installed (Chrome, Brave, Edge, or Chromium)
  • Feature flag: browser (enabled by default)

OpenCrabs auto-detects your default Chromium browser — no manual path configuration needed.

Browser Tools

ToolDescription
navigateOpen a URL in the browser
clickClick an element by CSS selector
typeType text into an input field
screenshotCapture a screenshot of the page
eval_jsExecute JavaScript in the page context
extract_contentExtract text content from elements
wait_for_elementWait for an element to appear

How It Works

The browser is lazy-initialized as a singleton — it only launches when the agent first needs it. It runs in stealth mode with a persistent profile directory, so cookies and sessions survive across tool calls.

On macOS, display auto-detection enables headed mode when a display is available, falling back to headless in CI or daemon environments.

Example

Ask the agent:

“Go to our staging site, log in with the test account, navigate to the dashboard, and take a screenshot”

The agent will chain navigatetype (username) → type (password) → click (login button) → navigate (dashboard) → screenshot — all autonomously.

Configuration

No configuration needed. The browser feature is enabled by default. To disable it at build time:

cargo build --release --no-default-features --features "telegram,discord,slack"

Cron Jobs

Schedule tasks to run on a recurring schedule. Cron jobs can run in isolated sessions or wake the main session.

CLI Management

# Add a job
opencrabs cron add \
  --name "Morning Report" \
  --cron "0 9 * * *" \
  --tz "Europe/London" \
  --prompt "Check emails, calendar, and give me a morning briefing" \
  --deliver-to telegram:123456

# List all jobs
opencrabs cron list

# Enable/disable (accepts name or ID)
opencrabs cron enable "Morning Report"
opencrabs cron disable "Morning Report"

# Remove (accepts name or ID)
opencrabs cron remove "Morning Report"

Agent Management

The agent can also manage cron jobs via the cron_manage tool:

"Create a cron job that checks my emails every morning at 9am"

Options

FlagDescription
--nameJob name (unique identifier)
--cronCron expression (e.g. 0 9 * * *)
--tzTimezone (e.g. America/New_York)
--promptThe prompt to send to the agent
--providerAI provider to use (optional)
--modelModel to use (optional)
--thinkingThinking mode: on, off, budget_XXk
--deliver-toChannel delivery: telegram:CHAT_ID, discord:CHANNEL_ID, HTTP webhook URL, or comma-separated multiple targets
--auto-approveAuto-approve tool use for this job

Multi-Target Delivery

deliver_to accepts comma-separated targets to send results to multiple destinations simultaneously:

opencrabs cron add \
  --name "Morning Report" \
  --cron "0 9 * * *" \
  --prompt "Give me a morning briefing" \
  --deliver-to "telegram:-12345,http://webhook.example.com/notify"

Supported targets in any combination:

  • telegram:CHAT_ID or telegram:-GROUP_ID
  • discord:CHANNEL_ID
  • slack:CHANNEL_ID
  • http://... or https://... (webhook URL)

Results are stored in the DB via the cron_results table regardless of delivery target, so you can query past execution results with opencrabs cron results <name>.

Heartbeat vs Cron

Use heartbeat (HEARTBEAT.md) when:

  • Checks are periodic but timing is flexible (~30 min)
  • You want to reduce API calls by batching
  • Tasks share the main session context

Use cron when:

  • Exact timing matters (“9:00 AM every Monday”)
  • Task needs isolation from main session
  • You want a different model or thinking level
  • Output should deliver to a specific channel

Plans

Plans provide structured multi-step task execution with a live progress widget in the TUI.

Creating a Plan

Ask the agent to plan a complex task:

"Plan the migration from PostgreSQL to SQLite"

The agent uses the plan tool internally to create a plan with:

  • Title and description
  • Technical stack
  • Risk assessment
  • Test strategy
  • Ordered tasks with dependencies and complexity ratings

Plan Lifecycle

  1. Draft — Agent creates the plan and adds tasks
  2. Finalize — Agent calls finalize which triggers the tool approval dialog
  3. Approved — You approve in the tool dialog, plan status becomes Approved, and the agent begins executing tasks immediately
  4. In Progress — Tasks execute in dependency order
  5. Completed — All tasks done

In ask mode (default), the finalize step triggers the tool approval dialog — you review the full plan before execution begins. In auto-approve mode, finalize is auto-approved and the agent plans and executes without pausing.

Task States

Each task in a plan can be:

  • Pending (·) — Waiting for dependencies
  • InProgress (▶) — Currently executing
  • Completed (✓) — Done
  • Skipped (✓) — Manually skipped
  • Failed (✗) — Execution failed
  • Blocked (·) — Dependencies not met

TUI Plan Widget

When a plan is active, a live checklist panel appears above the input box showing:

  • Plan title and progress counter (e.g. 3/7)
  • Progress bar — Visual ██████░░░░ bar with percentage
  • Task list — Up to 6 tasks visible with status icons and task numbers
  • Overflow indicator... (N more) when tasks exceed the visible limit

The widget updates in real-time as the agent completes each task.

Managing Plans

Plans are managed through natural language:

"Approve the plan"
"Reject the plan"
"What's the plan status?"
"Skip task 3"

The agent handles plan creation, approval, execution, and status reporting through the plan tool.

Multi-Agent Orchestration

OpenCrabs supports spawning specialized sub-agents that run autonomously in isolated sessions. Each child agent gets its own context, tool registry, and cancel token. Introduced in v0.2.97 with a typed agent system and team orchestration.

Agent Types

When spawning an agent, an agent_type parameter selects a specialized role with a curated tool set:

TypeRoleTools
generalFull-capability agent (default)All parent tools minus recursive/dangerous
exploreFast codebase navigation (read-only)read_file, glob, grep, ls
planArchitecture planning (read + analysis)read_file, glob, grep, ls, bash
codeImplementation (full write access)All parent tools minus recursive/dangerous
researchWeb search + documentation lookupread_file, glob, grep, ls, web_search, http_request

Each type receives a role-specific system prompt that shapes its behavior. Explore agents are fast and lightweight – they only read files. Code agents can modify anything. Research agents can search the web but not touch your filesystem.

Safety: ALWAYS_EXCLUDED Tools

No agent type has access to these tools, preventing dangerous or recursive operations:

  • spawn_agent – no spawning agents from agents
  • resume_agent, wait_agent, send_input, close_agent – no managing siblings
  • rebuild – no building from source
  • evolve – no self-updating

Five Orchestration Tools

ToolDescription
spawn_agentCreate a typed child agent to handle a sub-task autonomously in the background
wait_agentWait for a spawned agent to complete and return its output (configurable timeout)
send_inputSend follow-up instructions to a running agent (multi-turn conversation)
close_agentTerminate a running agent and clean up its resources
resume_agentResume a completed or failed agent with a new prompt (preserves prior context)

Spawn an Agent

spawn_agent(
  label: "refactor-auth",      # Human-readable label
  agent_type: "code",          # general | explore | plan | code | research
  prompt: "Refactor auth..."   # Task instruction
)

The agent runs in its own session with auto-approved tools. No blocking – it executes in the background while the parent continues.

Wait for Completion

wait_agent(
  agent_id: "abc-123",
  timeout_secs: 300            # Max wait time (default: 300s)
)

Multi-Turn with send_input

After spawning, you can send additional instructions without restarting:

send_input(
  agent_id: "abc-123",
  text: "Also add unit tests for the new module"
)

The child agent processes the input on its next iteration. This enables iterative workflows – review the agent’s output, then ask it to refine or continue.

Resume a Completed Agent

resume_agent(
  agent_id: "abc-123",
  prompt: "Now port the same changes to the other two files"
)

The agent continues in its original session, preserving all prior context. No need to re-explain the codebase.

Team Orchestration

The TeamManager coordinates named groups of agents for parallel execution. Three team-specific tools:

Create a Team

team_create(
  team_name: "backend-refactor",
  agents: [
    { label: "auth", agent_type: "code", prompt: "Refactor auth module" },
    { label: "tests", agent_type: "code", prompt: "Write tests for auth" },
    { label: "docs", agent_type: "general", prompt: "Update documentation" }
  ]
)

All agents spawn simultaneously and run in parallel. Returns the team name and all agent IDs.

Broadcast to a Team

team_broadcast(
  team_name: "backend-refactor",
  message: "Use the new AuthError enum instead of plain strings"
)

Sends a message to all running agents in the team. Non-running agents are skipped. Useful for sharing context or direction changes.

Delete a Team

team_delete(team_name: "backend-refactor")

Cancels all running agents and cleans up resources. Completed agents are left in the subagent manager for reference.

Subagent Provider/Model Config

By default, spawned agents inherit the parent’s provider and model. You can override this globally in config.toml:

[agent]
subagent_provider = "openrouter"   # Provider for child agents
subagent_model = "qwen/qwen3-235b" # Model override

This lets you run a powerful model (e.g. Claude Opus) for the main session while using a cheaper/faster model (e.g. Qwen) for sub-tasks. The override applies to all spawn_agent and resume_agent calls.

If subagent_provider or subagent_model is not set, the spawned agent loads from the global default provider.

Workflow Patterns

Parallel Research + Implementation

team_create("feature-research", [
  { label: "research", agent_type: "research", prompt: "Find best practices for rate limiting in Rust" },
  { label: "explore", agent_type: "explore", prompt: "Find all middleware files in the codebase" }
])

Wait for results, then spawn a code agent with the combined context.

Iterative Code Review

# 1. Spawn a code agent
spawn_agent(label: "impl", agent_type: "code", prompt: "Implement rate limiting middleware")

# 2. Wait for completion
wait_agent(agent_id: "impl-id")

# 3. Resume with refinements
resume_agent(agent_id: "impl-id", prompt: "Add tests for the edge cases we discussed")

Large-Scale Refactoring

team_create("refactor-team", [
  { label: "module-a", agent_type: "code", prompt: "Refactor module A to use the new trait" },
  { label: "module-b", agent_type: "code", prompt: "Refactor module B to use the new trait" },
  { label: "module-c", agent_type: "code", prompt: "Refactor module C to use the new trait" },
  { label: "tests", agent_type: "code", prompt: "Update all tests for the new trait signature" }
])

Testing

84 tests cover the entire multi-agent system:

  • Manager state machine (spawn, wait, close lifecycle)
  • SendInput wiring and input loop
  • CloseAgent cleanup
  • WaitAgent timeout behavior
  • AgentType tool filtering
  • TeamManager, TeamDelete, TeamBroadcast
  • Registry exclusion (ALWAYS_EXCLUDED enforcement)

Agent-to-Agent (A2A) Protocol

OpenCrabs includes a built-in A2A gateway implementing the A2A Protocol RC v1.0 for peer-to-peer agent communication.

Enabling

# config.toml
[a2a]
enabled = true
bind = "127.0.0.1"   # Loopback only (default) — use "0.0.0.0" to expose externally
port = 18790
# api_key = "your-secret"  # Optional Bearer token auth for incoming requests
# allowed_origins = ["http://localhost:3000"]  # CORS

Configuration Options

OptionDefaultDescription
enabledfalseEnable the A2A gateway
bind127.0.0.1Bind address — use 0.0.0.0 to accept external connections
port18790Gateway port
api_key(none)Bearer token for authenticating incoming requests. If set, all JSON-RPC requests must include Authorization: Bearer <key>
allowed_origins[]CORS allowed origins — no cross-origin requests unless explicitly set

Endpoints

EndpointMethodDescription
/.well-known/agent.jsonGETAgent Card — discover capabilities (auto-populated from tool registry)
/a2a/v1POSTJSON-RPC 2.0 — message/send, message/stream, tasks/get, tasks/cancel
/a2a/healthGETHealth check

Methods

  • message/send — Send a message to the agent, creates a task. Returns the task with result.
  • message/stream — Same as message/send but returns an SSE stream with real-time status updates and artifact chunks as the agent works.
  • tasks/get — Poll a task by ID to check status and retrieve results.
  • tasks/cancel — Cancel a running task.

Active tasks are persisted to the database and restored on restart.

The a2a_send Tool

The agent has a built-in a2a_send tool that lets it proactively communicate with remote A2A agents. This enables true bidirectional agent-to-agent communication.

Actions:

ActionDescription
discoverFetch a remote agent’s Agent Card to see its capabilities and skills
sendSend a task to a remote agent and wait for the result
getPoll a task by ID on a remote agent
cancelCancel a running task on a remote agent

The agent can use this tool autonomously — for example, delegating subtasks to a specialized remote agent.

Connecting Two Agents

Example: VPS + Local Machine

On VPS (~/.opencrabs/config.toml):

[a2a]
enabled = true
bind = "0.0.0.0"
port = 18790
api_key = "your-shared-secret"

On local machine (~/.opencrabs/config.toml):

[a2a]
enabled = true
bind = "127.0.0.1"
port = 18790

Connectivity Options

  1. SSH tunnel (recommended) — No ports to open, encrypted:

    # From local machine, tunnel VPS A2A to localhost:18791
    ssh -L 18791:127.0.0.1:18790 user@your-vps
    

    Local agent talks to http://127.0.0.1:18791/a2a/v1

  2. Direct — Open port 18790 on VPS firewall. Simple but exposes the port. Always use api_key with this approach.

  3. Reverse proxy — Nginx/Caddy on VPS with TLS + Bearer auth via api_key.

Examples

# Discover the agent
curl http://127.0.0.1:18790/.well-known/agent.json | jq .

# Send a message (with Bearer auth)
curl -X POST http://127.0.0.1:18790/a2a/v1 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-shared-secret" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "message/send",
    "params": {
      "message": {
        "role": "user",
        "parts": [{"text": "What tools do you have?"}]
      }
    }
  }'

# Stream a task (SSE)
curl -N -X POST http://127.0.0.1:18790/a2a/v1 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-shared-secret" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "message/stream",
    "params": {
      "message": {
        "role": "user",
        "parts": [{"text": "Analyze the system status"}]
      }
    }
  }'

# Poll a task
curl -X POST http://127.0.0.1:18790/a2a/v1 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-shared-secret" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tasks/get","params":{"id":"TASK_ID"}}'

# Cancel a task
curl -X POST http://127.0.0.1:18790/a2a/v1 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-shared-secret" \
  -d '{"jsonrpc":"2.0","id":4,"method":"tasks/cancel","params":{"id":"TASK_ID"}}'

# Health check
curl http://127.0.0.1:18790/a2a/health | jq .

Bee Colony Debate

Multi-agent structured debate via confidence-weighted voting (based on ReConcile, ACL 2024). Multiple “bee” agents argue across configurable rounds, enriched with knowledge context, then converge on a consensus answer.

Security

  • Loopback only by default — binds to 127.0.0.1
  • Bearer auth — set api_key to require Authorization: Bearer <key> on all JSON-RPC requests
  • CORS locked down — no cross-origin requests unless allowed_origins is set
  • For public exposure, use a reverse proxy with TLS + the api_key Bearer auth

Self-Healing

OpenCrabs monitors its own health and automatically recovers from failures without user intervention. All recovery events surface as visible notifications across TUI and all channels.

How It Differs from Crash Recovery

OpenCrabs has had crash recovery since early versions – if the process dies mid-request, pending requests are tracked in SQLite and automatically resumed on restart (see Pending Request Recovery below).

Self-healing (v0.2.92) goes further: the agent detects and fixes problems while it’s still running – corrupted config, degraded providers, context overflow, stuck streams, DB corruption – without restarting. Crash recovery is the safety net; self-healing prevents the fall.

Config Recovery

Every successful write to config.toml creates a snapshot at ~/.opencrabs/config.last_good.toml. When the config becomes corrupted or unparseable, OpenCrabs restores from the last-known-good snapshot automatically.

⚠️ Config was corrupted — restored from last-known-good snapshot (2 minutes ago)

A CONFIG_RECOVERED atomic flag tracks whether recovery happened during the current session, so downstream code can react accordingly.

Unknown Key Detection

Unknown top-level keys in config.toml trigger a startup warning listing the unrecognized entries. This catches typos like [teelgram] or [a2a_gatway] before they cause silent misconfiguration.

Known valid sections: [crabrace], [database], [logging], [debug], [providers], [channels], [agent], [daemon], [a2a], [image], [cron].

The [a2a] section also accepts gateway as an alias via serde, deduplicating a common typo.

Custom Provider Name Normalization

Provider names with mixed case or whitespace (e.g. "My Provider" vs "my provider") are normalized on load and save, preventing duplicate entries that would confuse the provider registry.

Provider Health Tracking

Per-provider success/failure history is persisted to ~/.opencrabs/provider_health.json. Each provider tracks:

  • last_success and last_failure (epoch seconds)
  • last_error (truncated to 200 chars)
  • consecutive_failures count (resets on success)
{
  "anthropic": {
    "last_success": 1743250500,
    "consecutive_failures": 0
  },
  "openai": {
    "last_success": 1743249800,
    "last_failure": 1743249700,
    "last_error": "rate_limit_exceeded",
    "consecutive_failures": 0
  }
}

The /doctor command surfaces health stats for every configured provider. Combined with the fallback provider chain, OpenCrabs detects degraded providers and routes to healthy ones automatically.

Source: src/config/health.rs (120 lines), integrated into src/brain/agent/service/helpers.rs.

DB Integrity Check

SQLite PRAGMA integrity_check runs at startup. If corruption is detected, a notification appears in TUI and all connected channels instead of silently failing.

Error Surfacing

v0.2.92 eliminated 14+ instances of silently swallowed errors across:

  • Config writes
  • Channel sends (Telegram, Discord, Slack, WhatsApp)
  • Tool connections (Slack, WhatsApp, Trello connect tools)
  • Pane state persistence

Before: let _ = ... and .ok() everywhere, errors vanish. After: Every error surfaces via logging or user notification.

Onboarding config writes use try_write! macros that batch errors during wizard steps and report them all at the end, so users see exactly what failed.

AgentService Config Propagation

AgentService::new() now requires an explicit &Config parameter instead of calling Config::load() internally. This eliminates hidden I/O, makes dependencies explicit, and enables test injection via AgentService::new_for_test().

Render, dialogs, messaging, and cron modules no longer call Config::load() internally – errors propagate up the call stack instead of being swallowed.

Context Budget Management

The agent enforces a 65% context budget threshold. When token usage reaches 65% of the effective context window (context limit minus tool schema overhead), automatic LLM compaction fires:

  1. Detect context usage ≥ 65% of effective max tokens
  2. Compact via LLM summarization (preserves meaning, not just truncation)
  3. Retry up to 3 times if compaction fails
  4. Second pass with tighter budget if still over threshold

The 65% threshold exists because providers like MiniMax degrade on function-calling quality well before hitting theoretical context limits – tool calls break around ~133k tokens of a 200k limit.

Source: src/brain/agent/service/tool_loop.rs (lines 14-112)

Emergency Compaction (ARG_MAX Recovery)

When CLI provider conversation context exceeds the OS ARG_MAX limit (~1MB on macOS), the agent recovers with a 3-stage fallback:

  1. Catch the “Argument list too long” or “prompt too large” error
  2. Emergency compact the conversation with an LLM summarization pass
  3. Insert a system marker so the agent knows context was compacted
  4. Retry the request

If compaction still fails, hard truncation kicks in – keeps last 24 messages (12 conversation pairs) with a marker telling the agent to use search_session for older context. Both markers persist to DB for recovery across sessions.

Both actions emit SelfHealingAlert progress events so users see exactly what happened.

Source: src/brain/agent/service/tool_loop.rs (lines 550-687), tested with ArgTooLongMockProvider and ContextLengthMockProvider in src/tests/cli_arg_too_long_test.rs (352 lines).

Stream Resilience

Stuck Loop Detection

Some streaming providers (notably MiniMax) occasionally loop the same content indefinitely without sending a stop signal. The agent detects this:

  • Maintains a 2048-byte rolling window of recent streamed text
  • When a 200+ byte substring from the second half appears in the first half, it’s a repeat
  • Stream is terminated immediately and retry logic fires

Source: src/brain/agent/service/helpers.rsdetect_text_repetition(), tested in src/tests/stream_loop_test.rs (15 tests)

Idle Timeout

If a stream goes silent for 60 seconds (API providers) or 10 minutes (CLI providers) with no events, it’s treated as a dropped connection.

CLI providers (Claude CLI, OpenCode CLI) run internal tools — cargo builds, tests, gh commands — that can take several minutes without producing stream events. The 60-second timeout caused premature termination on these, so CLI providers now get a 10-minute window before timeout fires.

If a stream goes silent:

#![allow(unused)]
fn main() {
const STREAM_IDLE_TIMEOUT: Duration = Duration::from_secs(60);
}

The tokio::select! loop races the stream against the timeout and the user’s cancellation token. Timeout triggers retry, not a hard error.

Pending Request Recovery

Crash recovery tracks every in-flight agent request in a pending_requests SQLite table. When a request starts, a row is inserted; when it completes (success or failure), the row is deleted.

On startup, any surviving rows mean the process crashed mid-request:

  1. Query pending_requests for interrupted rows
  2. Clear all rows (prevents double-recovery if this run also crashes)
  3. Dedup by session_id (resume each session only once)
  4. Spawn background tasks with a continuation prompt:

    “A restart just occurred while you were processing a request. Read the conversation context and continue where you left off naturally.”

  5. Emit TuiEvent::PendingResumed so the TUI shows a recovery notification

Source: src/db/repository/pending_request.rs, src/cli/ui.rs (lines 705-790)

Cross-Channel Crash Recovery (v0.2.93)

Before v0.2.93, pending request recovery always responded via the TUI — even if the original request came from Telegram, Discord, Slack, or WhatsApp. The resumed response would appear in the wrong place.

Now each channel passes its name and chat_id into run_tool_loop, which stores them in pending_requests. On restart, recovery routes responses back to the originating channel:

Original channelRecovery response goes to
TelegramSame Telegram chat
DiscordSame Discord channel
SlackSame Slack channel
WhatsAppSame WhatsApp chat
TrelloSame Trello board
TUITUI (as before)

The pending_requests table gained channel and channel_chat_id columns via a DB migration. get_interrupted_for_channel lets each channel handler query only its own pending rows. Selective delete_ids prevents one channel from clearing another channel’s recovery entries.

State Cleanup

Session deletion triggers cascade deletes across all related data:

  • Messages (full conversation history)
  • Usage ledger entries (token/cost records)
  • Channel messages (Telegram, Discord, Slack, WhatsApp delivery records)
  • Plans (autonomous plans created in the session)
  • Cron jobs (scheduled tasks bound to the session)
  • Cached pane state (stale split pane entries)

Custom provider names are normalized on load and save ("My Provider""my-provider"), preventing duplicate entries that would confuse the provider registry.

Model Selector Safety

Pressing Enter in the model selector no longer clears existing API keys. The selector preserves current configuration while switching models.

Model switching errors now surface the actual error with a ⚠️ prefix on all channels, instead of always showing “Model switched” even on failure.

UTF-8 Safety

split_message() across all 5 channel handlers (Telegram, Discord, Slack, WhatsApp, Trello) now uses is_char_boundary() to find safe split points, preventing panics on multi-byte characters (emojis, CJK, accented characters).

Cancel Persistence (v0.2.97)

When a user double-Escapes to abort a streaming response, the partial content is now persisted to the database before handle.abort() fires. This means cancelled content survives a session reload – you can scroll back and see exactly what the agent was saying before you stopped it.

Claude CLI Subprocess Cleanup

Previously, aborting a Claude CLI request would orphan the underlying claude subprocess. Now the stream reader loop monitors tx.closed() via tokio::select! and kills the child process when the receiver drops, preventing leaked subprocesses accumulating in the background.

Telegram Stale Delivery Suppression

When a request is cancelled mid-flight, the agent sometimes continued processing and delivered a stale response to Telegram. A cancel_token.is_cancelled() guard now fires before final delivery, preventing old agent results from posting after cancellation.

Config Overwrite Protection

The onboarding wizard previously overwrote existing channel settings on every save, causing data loss when re-running /onboard. apply_config() now scopes writes to only the current onboarding step. from_config() sets EXISTING_KEY_SENTINEL for all existing channel data, ensuring untouched fields are never overwritten.

Tool Description Wrapping

Tool call descriptions were previously truncated at 80 characters in the TUI. render_tool_group now wraps description headers and value lines to terminal width, and the 80-char pre-truncation of bash commands in format_tool_description has been removed. Long commands and file paths display fully.

Auto-Fallback on Rate Limits (v0.2.98)

When the primary provider hits a rate or account limit mid-stream, OpenCrabs catches the RateLimitExceeded error, saves the current conversation state, and resumes the same conversation on a fallback provider configured in [providers.fallback]:

[providers.fallback]
enabled = true
providers = ["openrouter", "anthropic"]  # tried in order

The fallback chain reads from config at startup. has_fallback_provider() and try_get_fallback_provider() are available at runtime for dynamic queries.

Two-Tier Context Budget Enforcement

Compaction budget scales proportionally to max_tokens instead of a hardcoded 170k, supporting custom providers with different context windows:

  • 65% soft trigger — LLM compaction with retries (preserves meaning)
  • 90% hard floor — Forced truncation to 75% (cannot fail)
  • Pre-truncate target: 85% of max_tokens
  • Compaction is silent to user — summary written to memory log only, no chat spam

Mid-Stream Decode Retry (v0.3.0)

Transient stream decoding errors now trigger a 3x backoff retry before falling back to the provider fallback chain. This reduces false provider switches caused by momentary network glitches.

SIGINT Handler + Panic Hook (v0.3.0)

Proper terminal restoration on crash or Ctrl+C via custom SIGINT handler and panic hook. No more garbled terminal after interrupt — the handler restores raw mode, cursor visibility, and alternate screen before exiting.

Proactive Rate Limiting (v0.2.99)

For OpenRouter :free models, OpenCrabs paces requests automatically using a shared global static limiter to avoid account-level bans. The rate limiter’s first-call sentinel (last_granted=0) no longer causes an unnecessary sleep.

Notifications

All self-healing events are delivered to:

  • TUI (status bar notification)
  • Telegram, Discord, Slack, WhatsApp (if connected)

Nothing happens silently. If the crab fixes itself, it tells you what it fixed.

Self-Improvement (RSI)

OpenCrabs improves itself over time through Recursive Self-Improvement (RSI). The agent analyzes its own performance, identifies patterns, and autonomously updates its own brain files.

How It Works

1. Feedback Collection

Every tool execution, user correction, and interaction is automatically logged to the feedback ledger. Categories include:

  • tool_success / tool_failure — whether tool calls worked
  • user_correction — when you corrected the agent’s behavior
  • provider_error — LLM stream drops, rate limits, timeouts
  • pattern_observed — recurring behaviors the agent notices

2. Pattern Analysis

The agent calls feedback_analyze to review its performance:

  • Per-tool success rates
  • Recent failure patterns
  • User correction frequency
  • Provider reliability trends

3. Autonomous Improvement

When patterns are identified, the agent calls self_improve to:

  • read: Load a brain file (SOUL.md, TOOLS.md, etc.) before modifying
  • apply: Append new instructions based on observed patterns
  • update: Surgically replace existing sections that need refinement
  • list: Show all previously applied improvements

4. Change Tracking

Every improvement is logged to ~/.opencrabs/rsi/improvements.md with:

  • Timestamp
  • Target file modified
  • Description of the change
  • Rationale (which feedback event triggered it)

Old improvements are archived to ~/.opencrabs/rsi/history/ to keep the active file lean.

Example

User: "stop including testing steps in your output"
  → feedback_record(event_type="user_correction", dimension="output_hygiene")
  
Agent notices pattern of 5+ corrections on output hygiene:
  → feedback_analyze(query="failures")
  → self_improve(action="apply", target_file="SOUL.md", 
    content="Never include testing steps or verification commands in user-facing output.")
  → Logged to rsi/improvements.md

Key Rules

  • No human approval needed for self-improvements — the agent identifies patterns and applies fixes directly
  • Surgical updates only — replaces specific sections, doesn’t rewrite entire files
  • Always reads before modifying — never blindly overwrites brain files
  • Archives old improvements — keeps the improvement log manageable

RSI Hardening (v0.3.10)

  • Cycle summaries no longer truncated — full text displays in TUI instead of cutting off mid-sentence
  • Phantom detection reduced to 2-signal requirement — needs both intent keyphrase AND zero tool calls before flagging, eliminating spurious self-heal triggers
  • Uses active provider — respects current provider/model config instead of hardcoded Anthropic
  • Persistent session reuse — one session per cycle, survives app restarts by persisting last_cycle timestamp
  • Skips unchanged feedback — if feedback count hasn’t changed, skips analysis to avoid wasted LLM calls

v0.3.11 Additions

  • DashScope migration — Qwen OAuth rotation replaced with simple API-key provider, deleting ~2,500 lines of complexity
  • Local model tool-call extraction — auto-extracts tool calls from text content: bare JSON {"tool_calls":[...]}, Claude-style XML <TOOLNAME><PARAM>value</PARAM></TOOLNAME>, and Qwen-specific <!-- tool_calls --> markers
  • 40+ TUI/self-heal fixes — narrowed phantom gate, split thinking per iteration, anti-code-block nudge for local models, tighter phantom scope, mid-turn “Let me see:” catch, backtick code reference detection
  • Per-session provider isolation — each session carries its own provider instance; no global swap affecting all sessions
  • Sub-agent AwaitingInput statewait_agent polls state and returns partial progress on timeout instead of deadlocking

Self-Healing vs Self-Improvement

Self-HealingSelf-Improvement
Fixes runtime errors (config corruption, DB issues)Fixes behavioral patterns (bad habits, user corrections)
Automatic, no analysis neededRequires feedback analysis first
Protects the system from crashingMakes the agent better over time
ImmediateAccumulates across sessions

Multi-Profile Support

Run multiple isolated OpenCrabs instances from a single installation. Each profile gets its own config, memory, sessions, brain files, skills, cron jobs, and gateway service.

Introduced in v0.2.94.

Why Profiles?

Common use cases:

  • Work vs personal — separate API keys, brain files, Telegram bots
  • Multiple clients — different persona and config per customer
  • Model experimentation — compare different provider setups without clobbering your main config
  • Staging vs production — test brain file changes on a staging profile before rolling to your main agent

Creating a Profile

# Create a new profile
opencrabs profile create hermes

# List all profiles
opencrabs profile list

# Show details for a profile
opencrabs profile show hermes

# Delete a profile
opencrabs profile delete hermes

Switching Profiles

There are two ways to use a non-default profile:

# CLI flag (per-session)
opencrabs -p hermes

# Environment variable (persistent)
export OPENCRABS_PROFILE=hermes
opencrabs

The default profile (~/.opencrabs/) works exactly as before — zero breaking changes.

Directory Structure

Each profile gets its own directory under ~/.opencrabs/profiles/<name>/:

~/.opencrabs/
├── config.toml          # default profile config
├── memory/              # default profile memory
├── sessions.db          # default profile sessions
└── profiles/
    ├── hermes/
    │   ├── config.toml
    │   ├── memory/
    │   ├── sessions.db
    │   ├── logs/
    │   └── layout/
    └── assistant/
        ├── config.toml
        └── ...

Profile Migration

Copy config and brain files from one profile to another:

# Copy from default to hermes
opencrabs profile migrate --from default --to hermes

# Overwrite existing files in target
opencrabs profile migrate --from default --to hermes --force

Migration copies all .md and .toml files plus the memory/ directory. It excludes the database, sessions, logs, and layout state — so the target profile starts fresh with the source’s personality and configuration, not its history.

Export and Import

Share profiles as portable archives:

# Export a profile as .tar.gz
opencrabs profile export hermes
# → creates hermes.tar.gz in current directory

# Import on another machine
opencrabs profile import ./hermes.tar.gz

Token-Lock Isolation

Two profiles cannot bind the same bot token simultaneously. Before connecting a Telegram, Discord, Slack, or Trello channel, OpenCrabs checks for existing token locks using PID-based lock files:

~/.opencrabs/locks/telegram_<token_hash>.lock

If another profile (still running) holds the lock, startup fails with a clear message. Stale locks (process dead) are automatically cleaned up.

This prevents split-brain scenarios where two agents fight over the same bot.

Profile-Aware Daemons

Install a separate OS service per profile:

# Install daemon for the hermes profile
opencrabs -p hermes service install

# Start it
opencrabs -p hermes service start

# macOS: creates com.opencrabs.daemon.hermes.plist
# Linux: creates opencrabs-hermes.service

Multiple profile daemons can run simultaneously as separate OS services, each with its own ports, bot connections, and config.

Per-Session Provider Isolation

Changing the provider in the TUI for one profile does not affect other active profiles or Telegram/Discord/Slack sessions. Each session remembers its own provider independently.

This was fixed in v0.2.95 where provider changes previously leaked across sessions.

Voice (TTS & STT)

OpenCrabs supports text-to-speech and speech-to-text with three modes: Off, API (cloud), or Local (on-device, zero cost).

Quick Setup

Run /onboard:voice in the TUI to configure everything interactively — model downloads, voice previews, and API keys are all handled by the wizard.

Speech-to-Text (STT)

Modes

ModeEngineCostLatencySetup
APIGroq Whisper (whisper-large-v3-turbo)Per-minute pricing~1sAPI key in keys.toml
Localwhisper.cpp (on-device)Free~2-5sAuto-downloads model

Local STT Models

ModelSizeQualitySpeed
local-tiny~75 MBGood for short messagesFastest
local-base~142 MBBetter accuracyFast
local-small~466 MBHigh accuracyModerate
local-medium~1.5 GBBest accuracySlower

Models auto-download from HuggingFace to ~/.local/share/opencrabs/models/whisper/ on first use.

Configuration

# config.toml
[voice]
stt_enabled = true
stt_mode = "local"              # "api" or "local"
local_stt_model = "local-tiny"  # local-tiny, local-base, local-small, local-medium

For API mode:

# keys.toml
[providers.stt.groq]
api_key = "your-groq-key"       # From console.groq.com

Text-to-Speech (TTS)

Modes

ModeEngineCostVoicesSetup
APIOpenAI TTS (gpt-4o-mini-tts)Per-character pricingalloy, echo, fable, onyx, nova, shimmerAPI key in keys.toml
LocalPiper (on-device)Free6 voicesAuto-downloads model

Local TTS Voices (Piper)

VoiceDescription
ryanUS Male (default)
amyUS Female
lessacUS Female
kristinUS Female
joeUS Male
coriUK Female

Models auto-download from HuggingFace to ~/.local/share/opencrabs/models/piper/. A Python venv is created automatically for the Piper runtime.

Configuration

# config.toml
[voice]
tts_enabled = true
tts_mode = "local"              # "api" or "local"
local_tts_voice = "ryan"        # ryan, amy, lessac, kristin, joe, cori

For API mode:

# config.toml
[voice]
tts_mode = "api"
tts_voice = "echo"              # OpenAI voice name
tts_model = "gpt-4o-mini-tts"   # OpenAI model
# keys.toml
[providers.tts.openai]
api_key = "your-openai-key"

Full Configuration Reference

# config.toml
[voice]
# Speech-to-Text
stt_enabled = true
stt_mode = "local"              # "api" or "local"
local_stt_model = "local-tiny"  # local-tiny, local-base, local-small, local-medium

# Text-to-Speech
tts_enabled = true
tts_mode = "local"              # "api" or "local"
tts_voice = "echo"              # API mode: OpenAI voice
tts_model = "gpt-4o-mini-tts"   # API mode: OpenAI model
local_tts_voice = "ryan"        # Local mode: Piper voice

How Voice Messages Work

When a voice message arrives on Telegram, WhatsApp, Discord, or Slack:

  1. Audio is decoded (OGG/Opus or WAV)
  2. Transcribed via STT (local whisper.cpp or Groq API)
  3. Agent processes the text and generates a response
  4. Response is converted to speech via TTS (local Piper or OpenAI API)
  5. Audio is encoded as OGG/Opus and sent back as a voice message

Local mode handles everything on-device — no API calls, no cost, no data leaves your machine.

Hardware Requirements

FeatureCPU RequirementNotes
Local STT (rwhisper)AVX2 (Haswell 2013+)Metal GPU on macOS Apple Silicon
Local TTS (Piper)No restrictionsTested on 2007 iMac — works on any x86/ARM
Local embeddingsAVX (Sandy Bridge 2011+)Falls back to FTS-only search

OpenCrabs detects CPU capabilities at runtime and hides unavailable options in the onboarding wizard. Local TTS (Piper) has no CPU limitations and should work on virtually any machine.

Building Without Voice

Voice features are enabled by default. To build without them (smaller binary):

cargo build --release --no-default-features --features telegram,whatsapp,discord,slack,trello

Feature flags: local-stt (whisper.cpp), local-tts (Piper).

Building from Source

Prerequisites

  • Rust 1.94+ (stable, nightly not required)
  • SQLite3 development headers
  • OpenSSL development headers (vendored by default)
  • pkg-config (Linux/macOS)

macOS

brew install sqlite3 pkg-config

Ubuntu / Debian

sudo apt install build-essential pkg-config libsqlite3-dev libssl-dev

Arch Linux

sudo pacman -S base-devel sqlite openssl pkg-config

Clone and Build

git clone https://github.com/adolfousier/opencrabs.git
cd opencrabs
cargo build --release

The binary is at target/release/opencrabs.

Feature Flags

OpenCrabs uses Cargo features to toggle channel support:

FeatureDefaultDescription
telegramYesTelegram bot via teloxide
discordYesDiscord bot via serenity
slackYesSlack bot via slack-morphism
whatsappYesWhatsApp via whatsapp-rust
trelloYesTrello integration
browserYesHeadless Chrome automation via CDP
profilingNopprof flamegraphs (Unix only)

Build with specific features:

# Minimal — TUI only, no channels
cargo build --release --no-default-features

# Only Telegram
cargo build --release --no-default-features --features telegram

Release Profile

The release profile is optimized for size and speed:

[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1
strip = true
panic = "abort"

There’s also a release-small profile for minimal binary size:

cargo build --profile release-small

Running Tests

cargo test --all-features

Linting

Always use clippy with all features:

cargo clippy --all-features

Self-Update

If you build from source, use git pull && cargo build --release instead of /evolve. The /evolve command downloads pre-built binaries from GitHub Releases.

Architecture

High-Level Overview

┌─────────────────────────────────────────────────┐
│          TUI (ratatui) + Split Panes             │
├────────┬────────┬──────────┬────────────────────┤
│Telegram│Discord │  Slack   │     WhatsApp       │
├────────┴────────┴──────────┴────────────────────┤
│                 Brain (Agent Core)               │
│  ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│  │ Providers│ │  Tools   │ │  Memory (3-tier) │ │
│  │ Registry │ │ +Dynamic │ │                  │ │
│  └──────────┘ └──────────┘ └──────────────────┘ │
├─────────────────────────────────────────────────┤
│   Services / DB (SQLite) │ Browser (CDP)         │
├─────────────────────────────────────────────────┤
│   A2A Gateway │ Cron Scheduler │ Sub-Agents      │
├─────────────────────────────────────────────────┤
│   Shared Channel Commands (commands.rs — 847 lines) │
├─────────────────────────────────────────────────┤
│   Self-Healing (config recovery, provider health, │
│   ARG_MAX compaction, error surfacing)             │
├─────────────────────────────────────────────────┤
│   Daemon Mode (health endpoint, auto-reconnect)  │
└─────────────────────────────────────────────────┘

Source Layout

src/
├── main.rs              # Entry point, CLI parsing
├── lib.rs               # Library root
├── cli/                 # CLI argument parsing (clap)
├── config/              # Configuration types, loading, health tracking
│   └── health.rs        # Provider health persistence (120 lines)
├── db/                  # SQLite database layer
│   ├── models.rs        # Data models (Session, Message, etc.)
│   └── repository/      # Query functions per entity
├── migrations/          # SQL migration files
├── services/            # Business logic layer
│   └── session.rs       # Session management service
├── brain/               # Agent core
│   ├── agent/           # Agent service, context, tool loop
│   │   └── service/     # Builder, context, helpers, tool_loop
│   ├── provider/        # LLM provider implementations
│   ├── tools/           # 50+ tool implementations
│   └── memory/          # 3-tier memory system
├── tui/                 # Terminal UI (ratatui + crossterm)
│   ├── app/             # App state, input, messaging
│   └── render/          # UI rendering modules
├── channels/            # Messaging platform integrations
│   ├── commands.rs      # Shared text command handler (847 lines)
│   ├── telegram/        # Teloxide-based bot
│   ├── discord/         # Serenity-based bot
│   ├── slack/           # Slack Socket Mode
│   └── whatsapp/        # WhatsApp Web pairing
├── a2a/                 # Agent-to-Agent gateway (axum)
├── cron/                # Cron job scheduler
├── memory/              # Vector search + FTS5
├── docs/                # Embedded doc templates
├── tests/               # Integration tests
└── benches/             # Criterion benchmarks

Key Crates

CratePurpose
ratatui + crosstermTerminal UI rendering and input
rusqlite + deadpool-sqliteSQLite database with connection pooling
reqwestHTTP client for LLM APIs
axum + tower-httpA2A HTTP gateway
crabraceProvider registry and routing
teloxideTelegram Bot API
serenityDiscord gateway
slack-morphismSlack API
qmd + llama-cpp-2Memory search (FTS5 + embeddings)
rwhisper (candle)Local STT — pure Rust, Metal GPU on macOS
piper (Python venv)Local TTS with OGG/Opus encoding
syntectSyntax highlighting in TUI
tiktoken-rsToken counting

Data Flow

  1. Input arrives from TUI, channel, A2A, or cron trigger
  2. Channel commands (/doctor, /help, /usage, /evolve) execute directly via the shared handler without LLM routing
  3. Brain builds context (system prompt + brain files + memory + conversation)
  4. Provider streams the LLM response via the selected provider; health is tracked per-provider
  5. Tool Loop executes any tool calls, feeds results back to the LLM. CLI provider segments (text/tool interleaving) are tracked for correct ordering
  6. Response is delivered back to the originating channel
  7. DB persists messages, token usage, session state, and CLI tool segments
  8. Self-healing monitors for config corruption, context budget overflow (65% threshold), ARG_MAX limits, stuck streams (2048-byte repeat detection), idle timeouts (60s), provider failures (per-provider health tracking with auto-failover), and DB integrity. Crash recovery replays pending requests on restart. All errors surfaced – nothing swallowed silently

Database

SQLite with WAL mode. Tables:

  • sessions — Session metadata, provider, model, working directory
  • messages — Conversation history per session
  • usage_ledger — Permanent token/cost tracking
  • memory_* — FTS5 and vector tables for semantic memory

Migrations run automatically on startup from src/migrations/.

Concurrency Model

  • Tokio async runtime with multi-threaded scheduler
  • Each channel runs as an independent tokio task
  • Sessions are isolated — each has its own conversation state
  • Tool execution uses tokio::task::block_in_place for sync operations
  • A2A gateway runs as a separate axum server task

Testing Guide

Comprehensive test coverage for OpenCrabs. All tests run with:

cargo test --all-features

Quick Reference

CategoryTestsLocation
Brain — Agent Service42src/brain/agent/service.rs
Brain — Prompt Builder20src/brain/prompt_builder.rs
Brain — Agent Context12src/brain/agent/context.rs
Brain — Provider (Anthropic)9src/brain/provider/anthropic.rs
Brain — Provider (Retry)9src/brain/provider/retry.rs
Brain — Provider (Custom OpenAI)9src/brain/provider/custom_openai_compatible.rs
Brain — Provider (Factory)4src/brain/provider/factory.rs
Brain — Provider (Copilot)8src/brain/provider/copilot.rs
Brain — Provider (Types/Error/Trait)7src/brain/provider/
Brain — Tokenizer8src/brain/tokenizer.rs
Brain — Commands6src/brain/commands.rs
Brain — Self-Update1src/brain/self_update.rs
Brain Tools — Plan Security20src/brain/tools/plan_tool.rs
Brain Tools — Exa Search18src/brain/tools/exa_search.rs
Brain Tools — Write File17src/brain/tools/write_opencrabs_file.rs
Brain Tools — A2A Send16src/brain/tools/a2a_send.rs
Brain Tools — Load Brain File14src/brain/tools/load_brain_file.rs
Brain Tools — Brave Search12src/brain/tools/brave_search.rs
Brain Tools — Doc Parser10src/brain/tools/doc_parser.rs
Brain Tools — Registry7src/brain/tools/registry.rs
Brain Tools — Slash Command6src/brain/tools/slash_command.rs
Brain Tools — Bash21src/brain/tools/bash.rs
Brain Tools — Write/Read/Config/Memory/Error16src/brain/tools/
Channels — Voice Service14src/channels/voice/service.rs
Channels — Voice Local TTS14src/channels/voice/local_tts.rs
Channels — Voice Local Whisper25src/channels/voice/local_whisper.rs
Channels — Commands14src/channels/commands.rs
Channels — WhatsApp Store15src/channels/whatsapp/store.rs
Channels — WhatsApp Handler5src/channels/whatsapp/handler.rs
Channels — Telegram Handler8src/channels/telegram/handler.rs
Channels — Slack Handler2src/channels/slack/handler.rs
Channels — Discord Handler2src/channels/discord/handler.rs
Channels — General5src/channels/
Config — Types19src/config/types.rs
Config — Secrets5src/config/secrets.rs
Config — Update4src/config/update.rs
Config — Crabrace3src/config/crabrace.rs
DB — Repository (Plan)15src/db/repository/plan.rs
DB — Retry8src/db/retry.rs
DB — Database5src/db/database.rs
DB — Models4src/db/models.rs
DB — Repository (Other)9src/db/repository/
Services — Plan11src/services/plan.rs
Services — File11src/services/file.rs
Services — Message10src/services/message.rs
Services — Session9src/services/session.rs
Services — Context2src/services/context.rs
A2A — Debate8src/a2a/debate.rs
A2A — Types6src/a2a/types.rs
A2A — Server/Handler/Agent Card7src/a2a/
Memory — Store6src/memory/store.rs
Memory — Search3src/memory/search.rs
Pricing13src/pricing.rs
Logging4src/logging/logger.rs
Utils — Install6src/utils/install.rs
Utils1src/utils/
CLI1src/cli.rs
Tests — CLI Parsing28src/tests/cli_test.rs
Tests — Cron Jobs & Scheduling49src/tests/cron_test.rs
Tests — Channel Search24src/tests/channel_search_test.rs
Tests — Voice STT Dispatch11src/tests/voice_stt_dispatch_test.rs
Tests — Voice Onboarding62src/tests/voice_onboarding_test.rs
Tests — Candle Whisper6src/tests/candle_whisper_test.rs
Tests — Evolve (Self-Update)23src/tests/evolve_test.rs
Tests — Session & Working Dir15src/tests/session_working_dir_test.rs
Tests — Message Compaction24src/tests/compaction_test.rs
Tests — Fallback Vision35src/tests/fallback_vision_test.rs
Tests — GitHub Copilot Provider38src/tests/github_provider_test.rs
Tests — File Extract36src/tests/file_extract_test.rs
Tests — Image Utils9src/tests/image_util_test.rs
Tests — Onboarding Brain21src/tests/onboarding_brain_test.rs
Tests — Onboarding Navigation26src/tests/onboarding_navigation_test.rs
Tests — Onboarding Types16src/tests/onboarding_types_test.rs
Tests — Onboarding Keys4src/tests/onboarding_keys_test.rs
Tests — OpenAI Provider16src/tests/openai_provider_test.rs
Tests — Plan Document15src/tests/plan_document_test.rs
Tests — TUI Error16src/tests/tui_error_test.rs
Tests — Queued Messages15src/tests/queued_message_test.rs
Tests — Custom Provider27src/tests/custom_provider_test.rs
Tests — Context Window14src/tests/context_window_test.rs
Tests — Onboarding Field Nav46src/tests/onboarding_field_nav_test.rs
Tests — Provider Sync10src/tests/provider_sync_test.rs
Tests — Brain Templates8src/tests/brain_templates_test.rs
Tests — Collapse Build Output9src/tests/collapse_build_output_test.rs
Tests — Reasoning Lines6src/tests/reasoning_lines_test.rs
Tests — AltGr Input8src/tests/altgr_input_test.rs
Tests — System Continuation6src/tests/system_continuation_test.rs
Tests — QR Render8src/tests/qr_render_test.rs
Tests — WhatsApp State7src/tests/whatsapp_state_test.rs
Tests — Post-Evolve5src/tests/post_evolve_test.rs
Tests — Stream Loop Detection15src/tests/stream_loop_test.rs
Tests — XML Tool Fallback10src/tests/xml_tool_fallback_test.rs
Tests — TUI Render Clear4src/tests/tui_render_clear_test.rs
Tests — Split Panes21src/tests/split_pane_test.rs
Tests — Slack Formatting21src/tests/slack_formatting_test.rs
Tests — Daemon Health10src/tests/daemon_health_test.rs
Tests — Claude CLI Cache5src/tests/claude_cli_cache_test.rs
Tests — Browser Headless4src/tests/browser_headless_test.rs
Tests — Provider Registry8src/tests/provider_registry_test.rs
Tests — Self-Healing System27src/tests/self_healing_test.rs
Tests — Emergency Compaction2src/tests/compaction_test.rs
Tests — Cross-Channel Crash Recovery12src/tests/pending_request_test.rs
Tests — Profile System57src/tests/profile_test.rs
Tests — Token Tracking29src/tests/token_tracking_test.rs
Tests — Cron Execution Storage6src/tests/cron_results_test.rs
Tests — LLM Artifact Stripping8src/tests/artifact_strip_test.rs
Tests — Subagent & Team Orchestration84src/tests/subagent_test.rs
Tests — Telegram Resume Pipeline55src/tests/telegram_resume_test.rs
Total1,995

Feature-Gated Tests

Some tests only compile/run with specific feature flags:

FeatureTests
local-sttLocal whisper inline tests, candle whisper tests, STT dispatch local-mode tests, codec tests, availability cycling tests
local-ttsTTS voice cycling, Piper voice Up/Down

All feature-gated tests use #[cfg(feature = "...")] and are automatically included when running with --all-features.


Running Tests

# Run all tests (recommended)
cargo test --all-features

# Run a specific test module
cargo test --all-features -- voice_onboarding_test

# Run a single test
cargo test --all-features -- is_newer_major_bump

# Run with output (for debugging)
cargo test --all-features -- --nocapture

# Run only local-stt tests
cargo test --features local-stt -- local_whisper

Disabled Test Modules

These modules exist but are commented out in src/tests/mod.rs (require network or external services):

ModuleReason
error_scenarios_testRequires mock API server
integration_testEnd-to-end with LLM provider
plan_mode_integration_testEnd-to-end plan workflow
streaming_testRequires streaming API endpoint

Contributing

Getting Started

  1. Fork the repository on GitHub
  2. Clone your fork and create a branch:
    git clone https://github.com/YOUR_USERNAME/opencrabs.git
    cd opencrabs
    git checkout -b my-feature
    
  3. Build and test:
    cargo clippy --all-features
    cargo test --all-features
    

Code Style

  • Run cargo clippy --all-features before committing — never cargo check
  • Follow existing patterns in the codebase
  • Keep changes focused — one feature or fix per PR
  • Add tests for new functionality in src/tests/

Pull Requests

  • Write a clear title and description
  • Reference any related issues
  • Ensure all tests pass
  • Keep PRs small and reviewable

Adding a New Tool

  1. Create a new file in src/brain/tools/
  2. Implement the tool handler function
  3. Register it in the tool registry
  4. Add the tool description to src/docs/reference/templates/TOOLS.md
  5. Add tests in src/tests/

Adding a New Provider

  1. Implement the provider in src/brain/provider/
  2. Register it in the provider registry via crabrace
  3. Add configuration docs to src/docs/reference/templates/
  4. Document setup in docs/src/brain/providers.md

Reporting Issues

Open an issue at github.com/adolfousier/opencrabs/issues with:

  • OpenCrabs version (opencrabs --version)
  • OS and architecture
  • Steps to reproduce
  • Expected vs actual behavior
  • Relevant log output (from ~/.opencrabs/logs/)

License

OpenCrabs is MIT licensed. By contributing, you agree that your contributions will be licensed under the same terms.

Security

Threat Model

OpenCrabs runs locally on your machine with access to your filesystem and shell. Security focuses on:

  1. API key protection — Keys never leave your machine except to their respective providers
  2. Network exposure — Minimal attack surface by default
  3. Tool execution — Sandboxed with user approval

API Key Storage

Keys are stored in ~/.opencrabs/keys.toml:

  • File permissions: 600 (owner read/write only)
  • Keys are loaded into memory with zeroize — zeroed on drop
  • Keys are never logged or included in conversation history
  • Keys are never sent to any provider other than their own

Network Security

A2A Gateway

  • Binds to 127.0.0.1 (loopback) by default
  • CORS disabled unless explicitly configured
  • No authentication built-in — use a reverse proxy for public exposure

Channel Connections

  • All channel APIs use TLS (HTTPS/WSS)
  • Telegram: long polling over HTTPS
  • Discord: WebSocket with TLS
  • Slack: Socket Mode (WebSocket)
  • WhatsApp: Noise protocol encryption

Tool Approval

Tools that modify your system require approval:

  • File writes — Shows the file path and diff
  • Shell commands — Shows the exact command before execution
  • Git operations — Push, commit, branch operations

Auto-approve mode (--auto-approve) bypasses this for automation use cases like cron jobs.

Data Storage

  • All data stored locally in ~/.opencrabs/opencrabs.db (SQLite)
  • No telemetry or analytics
  • No data sent to OpenCrabs servers (there are none)
  • Conversation history stays on your machine

Reporting Vulnerabilities

If you discover a security vulnerability, please report it responsibly:

  • Email: adolfo@meetneura.ai
  • Do not open a public issue for security vulnerabilities
  • We will acknowledge receipt within 48 hours

Changelog

Loading changelog from GitHub...