{"skill":{"slug":"ai-collab","displayName":"Ai Collab","summary":"Multi-agent autonomous collaboration system for two OpenClaw agents working in parallel. Use when setting up agent-to-agent communication, running a daemon a...","description":"---\nname: ai-collab\ndescription: \"Multi-agent autonomous collaboration system for two OpenClaw agents working in parallel. Use when setting up agent-to-agent communication, running a daemon agent alongside a primary agent, coordinating tasks between Claude and GPT instances, or establishing a shared chat log and inbox protocol. Triggers on: 'set up agent collaboration', 'run two agents', 'agent daemon', 'multi-agent', 'Jim and Clawdy', 'secondary agent', 'agent handoff'.\"\n---\n\n# ai-collab — Autonomous Multi-Agent Collaboration\n\nTwo OpenClaw agents working in parallel on shared tasks, coordinated via a structured chat log and daemon inbox protocol.\n\n## Architecture Overview\n\n```\n┌─────────────────────────────────────────────────────────┐\n│                     User (Jeremy)                       │\n│               Telegram / Direct Message                  │\n└──────────────────────┬──────────────────────────────────┘\n                       │\n         ┌─────────────┴──────────────┐\n         ▼                            ▼\n┌─────────────────┐         ┌──────────────────┐\n│   AGENT A       │         │   AGENT B        │\n│  (Jim / main)   │◄───────►│ (Clawdy / daemon)│\n│  claude code    │         │ claude --print    │\n│  port: main     │         │ inbox: filesystem │\n└────────┬────────┘         └────────┬─────────┘\n         │                           │\n         └──────────┬────────────────┘\n                    ▼\n         ┌──────────────────┐\n         │   chat.log       │ ← THE shared record\n         │   collab/inbox/  │ ← A→B messages\n         └──────────────────┘\n```\n\n**Agent A (Primary):** Interactive Claude Code session. Handles browser, complex tasks, user-facing responses.\n\n**Agent B (Daemon):** `claude --print` subprocess. Handles background tasks, monitoring, quick lookups. Triggered by messages dropped in inbox.\n\n---\n\n## Configuration\n\nAll settings via environment variables — no hardcoded values:\n\n```bash\n# ~/.openclaw/workspace/collab/.ai-collab.env\nexport AGENT_A_NAME=Jim\nexport AGENT_B_NAME=Clawdy\nexport AGENT_B_MODEL=claude-haiku-4-5-20251001   # Any claude --print compatible model\nexport AGENT_B_SESSION=clawdy-session             # tmux session name\nexport COLLAB_INBOX=$HOME/.openclaw/workspace/collab/inbox\nexport COLLAB_LOG=$HOME/.openclaw/workspace/collab/chat.log\n```\n\nSupported models for `AGENT_B_MODEL`:\n- `claude-haiku-4-5-20251001` — fastest, cheapest (recommended for daemon)\n- `claude-sonnet-4-6` — more capable, higher cost\n- Any OpenAI model if using the GPT daemon variant (see `examples/claude-gpt.md`)\n\n## Quick Setup\n\n```bash\n# 1. Source config\nsource ~/.openclaw/workspace/collab/.ai-collab.env\n\n# 2. Create the collab workspace\nmkdir -p \"$COLLAB_INBOX\"\n\n# 3. Start Agent B daemon (in a tmux session)\ntmux new-session -d -s \"$AGENT_B_SESSION\" \\\n  \"source ~/.openclaw/workspace/collab/.ai-collab.env && \\\n   bash ~/.openclaw/workspace/skills/ai-collab/scripts/daemon.sh\"\n\n# 4. Start message polling (Agent B → Agent A routing, runs every 60s via cron)\nbash ~/.openclaw/workspace/skills/ai-collab/scripts/poll_chatlog.sh &\n\n# 5. Test the link\nbash ~/.openclaw/workspace/skills/ai-collab/scripts/send.sh \"Hello from Agent A\"\n```\n\n---\n\n## Communication Protocol\n\nEvery message between agents follows this format. **No open loops.**\n\n| Tag | Direction | Meaning |\n|-----|-----------|---------|\n| `[TASK:name]` | A→B or B→A | Assign a task |\n| `[ACK:name]` | receiver | Acknowledged, starting work |\n| `[DONE:name]` | executor | Task complete + one-line result |\n| `[BLOCKED:name]` | executor | Can't complete + reason |\n| `[HANDOFF:name]` | either | \"Do X, reply [DONE:name] when finished\" |\n| `[STATUS:update]` | either | Async update on long-running task |\n| `[QUESTION:topic]` | either | Needs info before proceeding |\n\n**Rules:**\n1. Answer questions before asking new ones\n2. Close tasks before starting new ones\n3. Every message moves work forward or closes a loop\n4. Never: \"let me know\", \"ready when you are\", \"standing by\"\n\n**Example exchange:**\n```\nA → B: [TASK:price-check] Get BTC price from CoinGecko\nB → A: [ACK:price-check] Checking now.\nB → A: [DONE:price-check] BTC $94,230 as of 03:15 UTC\n```\n\n---\n\n## Daemon Script (Agent B)\n\n`scripts/daemon.sh` — drop in your collab directory:\n\n```bash\n#!/bin/bash\nPIDFILE=\"/tmp/agentb_daemon.pid\"\nif [ -f \"$PIDFILE\" ] && kill -0 \"$(cat $PIDFILE)\" 2>/dev/null; then\n  echo \"Daemon already running (PID $(cat $PIDFILE)). Exiting.\" >&2\n  exit 1\nfi\necho $$ > \"$PIDFILE\"\ntrap \"rm -f $PIDFILE\" EXIT\n\n# Required: unset so nested claude --print works\nunset CLAUDECODE\n\nINBOX=\"$HOME/.openclaw/workspace/collab/inbox\"\nLOG=\"$HOME/.openclaw/workspace/collab/chat.log\"\nmkdir -p \"$INBOX\"\n\nlogline() {\n  printf \"%s %s\\n\" \"$(date '+%Y-%m-%d %H:%M:%S')\" \"$1\" >> \"$LOG\"\n}\n\nlogline \"SYSTEM: Agent B daemon started\"\n\ninotifywait -m -e moved_to \"$INBOX\" 2>/dev/null | while read dir event file; do\n  FULLPATH=\"$INBOX/$file\"\n  [ ! -f \"$FULLPATH\" ] && continue\n\n  MSG=$(cat \"$FULLPATH\")\n  rm \"$FULLPATH\"\n\n  logline \"A -> B: $MSG\"\n\n  # Run Agent B (claude --print)\n  RESPONSE=$(claude --print --model claude-haiku-4-5-20251001 \\\n    \"You are Agent B. Agent A says: $MSG\nRespond in under 100 words. Use [DONE:taskname] or [BLOCKED:taskname] to close loops.\nContext: shared collab system. Chat log: $LOG\" 2>/dev/null)\n\n  logline \"B -> A: $RESPONSE\"\n\n  # Route response back to Agent A\n  openclaw agent --agent main -m \"[AgentB]: $RESPONSE\" --json > /dev/null 2>&1\ndone\n```\n\n---\n\n## Sending Messages (A → B)\n\n```bash\n# From Agent A, send to Agent B daemon inbox\nbash ~/.openclaw/workspace/skills/ai-collab/scripts/send.sh \"your message\"\n```\n\n**Atomic write pattern (prevents partial reads):**\n```bash\nINBOX=\"$HOME/.openclaw/workspace/collab/inbox\"\nTMPFILE=$(mktemp \"$INBOX/.msg.XXXXXX\")\necho \"$*\" > \"$TMPFILE\"\nmv \"$TMPFILE\" \"$INBOX/msg_$(date +%s%N).txt\"\n```\n\nAlways use `mktemp` + `mv` — never write directly to inbox. inotifywait fires on `moved_to`, not `close_write`.\n\n---\n\n## Chat Log Polling (B → A)\n\n`scripts/poll_chatlog.sh` — run via cron every 60s:\n\n```bash\n#!/bin/bash\nLOG=\"$HOME/.openclaw/workspace/collab/chat.log\"\nPTR_FILE=\"/tmp/chatlog_ptr\"\n\n[ ! -f \"$LOG\" ] && exit 0\n\nTOTAL=$(wc -l < \"$LOG\")\nLAST=$(cat \"$PTR_FILE\" 2>/dev/null || echo \"0\")\n[ \"$TOTAL\" -le \"$LAST\" ] && echo \"$TOTAL\" > \"$PTR_FILE\" && exit 0\n\nNEW=$(tail -n +\"$((LAST + 1))\" \"$LOG\" | grep \"B -> A:\" | sed 's/.*B -> A: //')\necho \"$TOTAL\" > \"$PTR_FILE\"\n[ -z \"$NEW\" ] && exit 0\n\nwhile IFS= read -r line; do\n  [ -z \"$line\" ] && continue\n  openclaw agent --agent main -m \"[AgentB]: $line\" --json > /dev/null 2>&1\ndone <<< \"$NEW\"\n```\n\nAdd to crontab:\n```\n* * * * * /bin/bash ~/.openclaw/workspace/collab/poll_chatlog.sh\n```\n\n---\n\n## Shared Filesystem Conventions\n\n```\n~/.openclaw/workspace/collab/\n  chat.log          # THE shared record — all messages logged here\n  inbox/            # A→B message queue (atomic mv only)\n  .env              # Shared secrets (chmod 600, never log)\n  task_queue.md     # Optional: structured task backlog\n  status_tracker.md # Optional: current task status per agent\n```\n\n**Logging to chat.log:**\n```bash\nprintf \"%s %s\\n\" \"$(date '+%Y-%m-%d %H:%M:%S')\" \"A -> B: [TASK:name] Description\" >> \"$LOG\"\n```\n\n**Rules:**\n- Never log secrets from `.env`\n- Always timestamp every line\n- Prefix with sender: `A -> B:` or `B -> A:` or `SYSTEM:` or `JEREMY ->`\n\n---\n\n## Telegram Bridge (Optional)\n\nRoute user Telegram messages into Agent B's inbox. Full setup guide: `references/telegram-bridge.md`\n\n**Quick summary:**\n1. Create a bot via [@BotFather](https://t.me/BotFather) → get `BOT_TOKEN`\n2. Add bot to your group → get `GROUP_ID` (negative number, e.g. `-1001234567890`)\n3. Disable Group Privacy Mode in BotFather so bot can read all messages\n4. Get your Telegram `USER_ID` from [@userinfobot](https://t.me/userinfobot)\n5. Set in `~/.openclaw/.env`: `TELEGRAM_BOT_TOKEN`, `TELEGRAM_GROUP_ID`, `TELEGRAM_USER_ID`\n6. Run the bridge in tmux: `tmux new-session -d -s tg-bridge \"bash references/telegram-bridge.md\"`\n\n```bash\n# Minimal bridge loop (inline version):\nsource ~/.openclaw/.env\nOFFSET_FILE=\"/tmp/tg_offset\"\nwhile true; do\n  OFFSET=$(cat \"$OFFSET_FILE\" 2>/dev/null || echo \"0\")\n  UPDATES=$(curl -s \"https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getUpdates?offset=$((OFFSET+1))&timeout=20\")\n  # Parse updates, drop user messages into inbox with USER: prefix\n  # See references/telegram-bridge.md for full parsing implementation\n  sleep 1\ndone\n```\n\nSee `references/telegram-bridge.md` for the complete production-ready implementation with message parsing, offset tracking, and error handling.\n\n---\n\n## Agent Configurations\n\nSee `examples/` for full configs:\n\n### Claude ↔ Claude (Jim + Clawdy)\n- Agent A: `claude code` (interactive, full tool access)\n- Agent B: `claude --print claude-haiku-4-5-20251001` (fast, scripting-optimized)\n- Best for: heavy task parallelism, one agent researches while other implements\n\n### Claude ↔ GPT\n- Agent A: Claude Code (full tool use)\n- Agent B: `openai api chat.completions.create` via script\n- Best for: cross-model verification, Claude builds → GPT reviews\n\n### GPT ↔ GPT\n- Agent A: GPT-4o via `openai` CLI\n- Agent B: GPT-4o-mini for fast background checks\n- Best for: speed + cost optimization when all context is OpenAI\n\n---\n\n## Task Handoff Pattern\n\nWhen Agent A needs Agent B to own a task completely:\n\n```\nA → B: [HANDOFF:data-fetch] Fetch all BTC trades from Kraken API last 7 days.\n       Save to ~/.openclaw/workspace/collab/kraken_trades.json.\n       Reply [DONE:data-fetch] when finished.\n\nB → A: [ACK:data-fetch] Fetching now.\nB → A: [DONE:data-fetch] 847 trades saved to kraken_trades.json. Date range: 2026-02-15 to 2026-02-22.\n```\n\nAgent A does not check on progress — waits for DONE or BLOCKED.\n\n---\n\n## Approval Pattern\n\nWhen Agent B's daemon needs user approval for a terminal command:\n\n```bash\n# From Agent A / user terminal:\nbash ~/.openclaw/workspace/skills/ai-collab/scripts/approve.sh \"Yes\"\n# or for numbered selections:\nbash ~/.openclaw/workspace/skills/ai-collab/scripts/approve.sh \"2\"\n```\n\n`approve.sh` sends keystrokes to the tmux session running Agent B:\n```bash\nSESSION=$(tmux ls | grep agentb-session | head -1 | cut -d: -f1)\ntmux send-keys -t \"$SESSION\" \"$1\" Enter\n```\n\n---\n\n## Rate Limiting\n\nAgent B should implement a rate governor to prevent runaway API calls:\n\n```bash\n# In daemon loop, before calling claude --print:\nCALLS_FILE=\"/tmp/agentb_calls\"\nWINDOW=60  # seconds\nMAX_CALLS=10\n\n# Count calls in last window\nRECENT=$(awk -v cutoff=\"$(($(date +%s) - WINDOW))\" '$1 > cutoff' \"$CALLS_FILE\" 2>/dev/null | wc -l)\nif [ \"$RECENT\" -ge \"$MAX_CALLS\" ]; then\n  logline \"SYSTEM: Rate limited — $RECENT calls in ${WINDOW}s\"\n  sleep 10\n  continue\nfi\ndate +%s >> \"$CALLS_FILE\"\n```\n\n---\n\n## Financial Gate Protocol (TIERED — updated 2026-02-22)\n\n**Three tiers based on amount:**\n\n| Tier | Amount | Rule |\n|------|--------|------|\n| 1 | Under $20 | Either agent acts independently — no approval needed |\n| 2 | $20–$50 | Both agents PROPOSE + APPROVE before acting |\n| 3 | Over $50 | Requires `[AUTHORIZED:financial:amount:timestamp:Jeremy]` tag |\n\n```bash\n# Tier 3 tag format (Jeremy must write to chat.log):\n[AUTHORIZED:financial:buy:BTC:$100:2026-02-22:Jeremy]\n\n# Tier 2 example flow:\n# Clawdy proposes: \"PROPOSE: buy $35 of SOL for DePIN gas — approve?\"\n# Jim approves:    \"APPROVED: buy $35 SOL\"\n# Then Clawdy acts.\n```\n\n**Daemon tiered gate logic:**\n```bash\n# <$20: proceed. $20-50: flag as tier2. >$50: block without AUTHORIZED tag.\nAMOUNT=$(echo \"$MSG\" | grep -oP '[$]?\\d+' | head -1 | tr -d '$')\nif [ -n \"$AMOUNT\" ] && [ \"$AMOUNT\" -gt 50 ] && ! echo \"$MSG\" | grep -q \"\\[AUTHORIZED:financial:\"; then\n  logline \"BLOCKED:financial-gate:tier3 — amount>$50, no AUTHORIZED tag\"; continue\nelif [ -n \"$AMOUNT\" ] && [ \"$AMOUNT\" -ge 20 ]; then\n  logline \"FINANCIAL:tier2 — propose before acting\"\nfi\n```\n\nIf Tier 3 blocked: log `[BLOCKED:financial-gate:tier3]`, send Telegram alert, do NOT execute.\n\n---\n\n## Daemon Watchdog Pattern\n\nCheck daemon health every 15 minutes. If silent >15 min, restart:\n\n```bash\n# check_daemon.sh (add to crontab: */15 * * * *)\nPIDFILE=\"/tmp/agentb_daemon.pid\"\nLOG=\"$HOME/.openclaw/workspace/collab/chat.log\"\n\n# Check PID alive\npid_alive=0\n[ -f \"$PIDFILE\" ] && kill -0 \"$(cat $PIDFILE)\" 2>/dev/null && pid_alive=1\n\n# Check last activity within 15 min\nlast_ts=$(grep -oP '^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}' \"$LOG\" 2>/dev/null | tail -1)\nrecent=0\nif [ -n \"$last_ts\" ]; then\n  age=$(( ($(date +%s) - $(date -d \"$last_ts\" +%s 2>/dev/null || echo 0)) / 60 ))\n  [ \"$age\" -lt 15 ] && recent=1\nfi\n\nif [ \"$pid_alive\" = \"0\" ] || [ \"$recent\" = \"0\" ]; then\n  tmux send-keys -t agentb-session \"bash daemon.sh\" Enter\nfi\n```\n\n---\n\n## Task Takeover Threshold\n\nIf Agent A (Jim) blocks on the same task **twice**, Agent B (Clawdy) takes it over:\n\n```\nB → A: [TASK:fetch-data] Fetch X. Reply [DONE:fetch-data].\n# 10 min timer...\nA → B: [BLOCKED:fetch-data] Can't access endpoint.\nB → A: [RETRY:fetch-data] Try alternate: curl -s https://backup-endpoint.com/x\n# Another 10 min...\nA → B: [BLOCKED:fetch-data] Still failing.\n# Clawdy takes over immediately:\nB: *executes task directly, logs [DONE:fetch-data] to chat.log*\n```\n\nRule: **Blocked 2x on same task → take it over, don't reassign.**\n\n---\n\n## Daemon Error Diagnosis\n\nWhen daemon produces blank/error responses:\n\n1. Check `/tmp/clawdy_last_err` — contains last stderr from `claude --print`\n2. Check ANSI-stripped chat.log for `CLAWDY_ERR:` lines\n3. Verify RESPONSE trimming line not corrupted (common issue: accidentally set to `RESPONSE=\"\"`)\n4. Restart daemon: `kill $(cat /tmp/clawdy_daemon.pid) && sleep 1 && bash clawdy_daemon.sh`\n\n**Auto-approve**: Use `Bash(*)` in `~/.claude/settings.local.json`. **NEVER** use tmux send-keys cron — it sends keypresses blindly to the wrong sessions.\n","topics":["Multi Agent"],"tags":{"latest":"2.0.0"},"stats":{"comments":0,"downloads":1256,"installsAllTime":47,"installsCurrent":2,"stars":0,"versions":2},"createdAt":1771804867224,"updatedAt":1779077259011},"latestVersion":{"version":"2.0.0","createdAt":1772231577288,"changelog":"ai-collab v2.0.0 changelog\n\n- Major version release with formatting and metadata updates.\n- SKILL.md and _meta.json modified; content and core instructions unchanged.\n- No functional or protocol changes—existing users do not need to update configuration or scripts.","license":null},"metadata":null,"owner":{"handle":"jeremysommerfeld8910-cpu","userId":"s170dn874bx3fny0j9t8chwjrn885qkc","displayName":"jeremysommerfeld8910-cpu","image":"https://avatars.githubusercontent.com/u/240074820?v=4"},"moderation":{"isSuspicious":false,"isMalwareBlocked":false,"verdict":"clean","reasonCodes":["review.llm_review"],"summary":"Review: review.llm_review","engineVersion":"v2.4.24","updatedAt":1779950881381}}