ZooBot
AGENTS.md1 starsChanged 7 months agoMITView on GitHub
ZooBot supports running multiple AI agents simultaneously, each with its own isolated workspace, configuration, and conversation state. This allows you to have specialized agents for different tasks while maintaining complete isolation. The agent management feature enables you to: When a message arrives, the queue processor parses it for routing: Routing Rules: Each agent has its own configuration in .zoobot/settings.json:
- Reads credentials
- Installs packages
- Sends data out
We split this AGENTS.md into the rules it gives an agent
10 rules. About 0 are common, 4 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 63
When a message arrives, the queue processor parses it for routing:
- Distinctive: line 74
No prefix → Routes to default agent (user-named during setup)
- Distinctive: line 76
No agents configured → Uses legacy single-agent mode
- Very specific: line 265
If both prompt_file and system_prompt are provided, prompt_file takes precedence
- Distinctive: line 400
Use different AI providers for different tasks:
- Very specific: line 455
If no agents are configured, ZooBot automatically creates a default agent using the legacy models section:
- Very specific: line 665
Use the custom:<provider_id> prefix as the agent's provider:
- Very specific: line 693
When an agent with provider: "custom:<id>" is invoked:
- Very specific: line 796
When you message an agent directly (e.g., @coder fix this), team context is automatically activated if the agent belongs to a team.
- Very specific: line 800
When an agent is added to a team, its AGENTS.md file is automatically updated with a team collaboration section listing teammates and …
≈ “Common” is an estimate: at least 1 in 5 of the 36,368 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Agents
ZooBot supports running multiple AI agents simultaneously, each with its own isolated workspace, configuration, and conversation state. This allows you to have specialized agents for different tasks while maintaining complete isolation.
Overview
The agent management feature enables you to:
- Run multiple agents with different models, providers, and configurations
- Route messages to specific agents using
@agent_idsyntax - Isolate conversations - each agent has its own workspace directory and conversation history
- Specialize agents - give each agent a custom system prompt and configuration
- Switch providers - mix Anthropic (Claude) and OpenAI (Codex) agents
- Customize workspaces - organize agents in your own workspace directory
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Message Channels │
│ (Discord, Telegram, WhatsApp) │
└────────────────────┬────────────────────────────────────────┘
│
│ User sends: "@coder fix the bug"
↓
┌─────────────────────────────────────────────────────────────┐
│ Queue Processor │
│ • Parses @agent_id routing prefix │
│ • Falls back to default agent if no prefix │
│ • Loads agent configuration from settings.json │
└────────────────────┬────────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ Agent Router │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ @coder │ │ @writer │ │ @assistant │ │
│ │ │ │ │ │ (default) │ │
│ │ Provider: │ │ Provider: │ │ Provider: │ │
│ │ anthropic │ │ openai │ │ anthropic │ │
│ │ Model: │ │ Model: │ │ Model: │ │
│ │ sonnet │ │ gpt-5.3-codex│ │ opus │ │
│ │ │ │ │ │ │ │
│ │ Workspace: │ │ Workspace: │ │ Workspace: │ │
│ │ ~/workspace/ │ │ ~/workspace/ │ │ ~/workspace/ │ │
│ │ coder/ │ │ writer/ │ │ assistant/ │ │
│ │ │ │ │ │ │ │
│ │ Config: │ │ Config: │ │ Config: │ │
│ │ .claude/ │ │ .claude/ │ │ .claude/ │ │
│ │ heartbeat.md │ │ heartbeat.md │ │ heartbeat.md │ │
│ │ AGENTS.md │ │ AGENTS.md │ │ AGENTS.md │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ Shared: ~/.zoobot/ (channels, files, logs, zoobot.db) │
└─────────────────────────────────────────────────────────────┘How It Works
1. Message Routing
When a message arrives, the queue processor parses it for routing:
// User sends: "@coder fix the authentication bug"
const routing = parseAgentRouting(rawMessage, agents);
// Result: { agentId: "coder", message: "fix the authentication bug" }Routing Rules:
- Message starts with
@agent_id→ Routes to that agent - No prefix → Routes to default agent (user-named during setup)
- Agent not found → Falls back to default agent
- No agents configured → Uses legacy single-agent mode
2. Agent Configuration
Each agent has its own configuration in .zoobot/settings.json:
{
"workspace": {
"path": "/Users/me/zoobot-workspace",
"name": "zoobot-workspace"
},
"agents": {
"coder": {
"name": "Code Assistant",
"provider": "anthropic",
"model": "sonnet",
"working_directory": "/Users/me/zoobot-workspace/coder",
"system_prompt": "You are a senior software engineer..."
},
"writer": {
"name": "Technical Writer",
"provider": "openai",
"model": "gpt-5.3-codex",
"working_directory": "/Users/me/zoobot-workspace/writer",
"prompt_file": "/path/to/writer-prompt.md"
},
"assistant": {
"name": "Assistant",
"provider": "anthropic",
"model": "opus",
"working_directory": "/Users/me/zoobot-workspace/assistant"
}
}
}Note: The working_directory is automatically set to <workspace>/<agent_id>/ when creating agents via zoobot agent add.
3. Agent Isolation
Each agent has its own isolated workspace directory with complete copies of configuration files:
Agent Workspaces:
~/zoobot-workspace/ # Or custom workspace name
├── coder/
│ ├── .claude/ # Agent's own Claude config
│ │ ├── settings.json
│ │ ├── settings.local.json
│ │ └── hooks/
│ │ ├── session-start.sh
│ │ └── log-activity.sh
│ ├── heartbeat.md # Agent-specific heartbeat
│ ├── AGENTS.md # Agent-specific docs
│ └── reset_flag # Reset signal
├── writer/
│ ├── .claude/
│ ├── heartbeat.md
│ ├── AGENTS.md
│ └── reset_flag
└── assistant/ # User-named default agent
├── .claude/
├── heartbeat.md
├── AGENTS.md
└── reset_flagTemplates & Shared Resources:
Templates and shared resources are stored in ~/.zoobot/:
~/.zoobot/
├── .claude/ # Template: Copied to each new agent
├── heartbeat.md # Template: Copied to each new agent
├── AGENTS.md # Template: Copied to each new agent
├── channels/ # SHARED: Channel state (QR codes, ready flags)
├── files/ # SHARED: Uploaded files from all channels
├── logs/ # SHARED: Log files for all agents and channels
└── zoobot.db # SHARED: SQLite message queueHow it works:
- Each agent runs CLI commands in its own workspace directory (
~/workspace/agent_id/) - Each agent gets its own copy of
.claude/,heartbeat.md, andAGENTS.mdfrom templates - Agents can customize their settings, hooks, and documentation independently
- Conversation history is isolated per agent (managed by Claude/Codex CLI)
- Reset flags allow resetting individual agent conversations
- File operations happen in the agent's directory
- Templates stored in
~/.zoobot/are copied when creating new agents - Uploaded files, the SQLite queue, and logs are shared (common dependencies)
4. Provider Execution
The queue processor calls the appropriate CLI based on provider:
Anthropic (Claude):
cd "$agent_working_directory" # e.g., ~/zoobot-workspace/coder/
claude --dangerously-skip-permissions \
--model claude-sonnet-4-6 \
--system-prompt "Your custom prompt..." \
-c \ # Continue conversation
-p "User message here"OpenAI (Codex):
cd "$agent_working_directory" # e.g., ~/zoobot-workspace/coder/
codex exec resume --last \
--model gpt-5.3-codex \
--skip-git-repo-check \
--dangerously-bypass-approvals-and-sandbox \
--json \
"User message here"Configuration
Initial Setup
During first-time setup (zoobot setup), you'll be prompted for:
- Workspace name - Where to store agent directories
- Default:
zoobot-workspace - Creates:
~/zoobot-workspace/
- Default:
- Default agent name - Name for your main assistant
- Default:
assistant - This replaces the hardcoded "default" agent
- Default:
Adding Agents
Interactive CLI:
zoobot agent addThis walks you through:
- Agent ID (e.g.,
coder) - Display name (e.g.,
Code Assistant) - Provider (Anthropic or OpenAI)
- Model selection
- Optional system prompt
Working directory is automatically set to: <workspace>/<agent_id>/
Manual Configuration:
Edit .zoobot/settings.json:
{
"workspace": {
"path": "/Users/me/zoobot-workspace",
"name": "zoobot-workspace"
},
"agents": {
"researcher": {
"name": "Research Assistant",
"provider": "anthropic",
"model": "opus",
"working_directory": "/Users/me/zoobot-workspace/researcher",
"system_prompt": "You are a research assistant specialized in academic literature review and data analysis."
}
}
}Agent Fields
| Field | Required | Description |
name | Yes | Human-readable display name |
provider | Yes | anthropic, openai, opencode, or custom:<provider_id> |
model | Yes | Model identifier (e.g., sonnet, opus, gpt-5.3-codex) |
working_directory | Yes | Directory where agent operates (auto-set to <workspace>/<agent_id>/) |
system_prompt | No | Inline system prompt text |
prompt_file | No | Path to file containing system prompt |
Note:
- If both
prompt_fileandsystem_promptare provided,prompt_filetakes precedence - The
working_directoryis automatically set to<workspace>/<agent_id>/when creating agents - Each agent gets its own isolated directory with copies of templates from
~/.zoobot/
Usage
Routing Messages to Agents
In any messaging channel (Discord, Telegram, WhatsApp):
@coder fix the authentication bug in login.ts
@writer document the new API endpoints
@researcher find papers on transformer architectures
help me with this (goes to default agent - "assistant" by default)Listing Agents
From chat:
/agentsFrom CLI:
zoobot agent listOutput:
Configured Agents
==================
@coder - Code Assistant
Provider: anthropic/sonnet
Directory: /Users/me/zoobot-workspace/coder
@writer - Technical Writer
Provider: openai/gpt-5.3-codex
Directory: /Users/me/zoobot-workspace/writer
Prompt: /path/to/writer-prompt.md
@assistant - Assistant
Provider: anthropic/opus
Directory: /Users/me/zoobot-workspace/assistantManaging Agents
Show agent details:
zoobot agent show coderReset agent conversation:
zoobot agent reset coderFrom chat:
@coder /resetRemove agent:
zoobot agent remove coderUse Cases
Specialized Codebases
Have different agents for different projects:
{
"workspace": {
"path": "/Users/me/my-workspace"
},
"agents": {
"frontend": {
"working_directory": "/Users/me/my-workspace/frontend",
"system_prompt": "You are a React and TypeScript expert..."
},
"backend": {
"working_directory": "/Users/me/my-workspace/backend",
"system_prompt": "You are a Node.js backend engineer..."
}
}
}Usage:
@frontend add a loading spinner to the dashboard
@backend optimize the database queries in user serviceRole-Based Agents
Assign different roles to agents:
{
"agents": {
"reviewer": {
"system_prompt": "You are a code reviewer. Focus on security, performance, and best practices."
},
"debugger": {
"system_prompt": "You are a debugging expert. Help identify and fix bugs systematically."
},
"architect": {
"model": "opus",
"system_prompt": "You are a software architect. Design scalable, maintainable systems."
}
}
}Provider Mixing
Use different AI providers for different tasks:
{
"custom_providers": {
"openrouter": {
"name": "OpenRouter",
"harness": "claude",
"base_url": "https://openrouter.ai/api/v1",
"api_key": "sk-or-..."
}
},
"agents": {
"quick": {
"provider": "anthropic",
"model": "sonnet",
"system_prompt": "Fast, efficient responses for quick questions."
},
"deep": {
"provider": "anthropic",
"model": "opus",
"system_prompt": "Thorough, detailed analysis for complex problems."
},
"codegen": {
"provider": "openai",
"model": "gpt-5.3-codex",
"system_prompt": "Code generation specialist."
},
"proxy-agent": {
"provider": "custom:openrouter",
"model": "claude-sonnet-4-6",
"system_prompt": "Uses a custom API endpoint."
}
}
}Advanced Features
Dynamic Agent Routing
You can pre-route messages from channel clients by setting the agent field:
// In channel client (discord-client.ts, etc.)
const queueData: QueueData = {
channel: 'discord',
message: userMessage,
agent: 'coder', // Pre-route to specific agent
// ...
};Fallback Behavior
If no agents are configured, ZooBot automatically creates a default agent using the legacy models section:
{
"models": {
"provider": "anthropic",
"anthropic": {
"model": "sonnet"
}
}
}This ensures backward compatibility with older configurations.
Global Model & Provider Commands
The zoobot model and zoobot provider --model commands update both the global default and propagate to all matching agents:
zoobot model sonnet— updates.models.anthropic.modeland setsmodel = "sonnet"on every agent withprovider == "anthropic".zoobot model gpt-5.3-codex— updates.models.openai.modeland setsmodel = "gpt-5.3-codex"on every agent withprovider == "openai".zoobot provider openai --model gpt-5.3-codex— switches the global provider, and updates all agents that were on the old provider to the new provider and model.zoobot provider anthropic(no--model) — only switches the global default; agents are not changed.
To change a single agent's provider/model without affecting others, use:
zoobot agent provider <agent_id> <provider> --model <model>Running zoobot model or zoobot provider with no arguments shows the global default followed by a per-agent breakdown.
Reset Flags
Per-agent reset: <workspace>/<agent_id>/reset_flag - resets a specific agent's conversation.
Reset flags are automatically cleaned up after use.
Reset one or more agents:
zoobot reset coder
zoobot reset coder researcherCustom Workspaces
You can create multiple workspaces for different purposes:
{
"workspace": {
"path": "/Users/me/work-projects",
"name": "work-projects"
}
}Or even use cloud-synced directories:
{
"workspace": {
"path": "/Users/me/Dropbox/zoobot-workspace",
"name": "zoobot-workspace"
}
}File Handling
Files uploaded through messaging channels are automatically available to all agents:
User uploads image.png via Telegram
→ Saved to ~/.zoobot/files/telegram_123456_image.png
→ Message includes: [file: /path/to/image.png]
→ Routed to agent
→ Agent can read/process the fileAgents can also send files back:
// Agent response includes:
response = "Here's the diagram [send_file: /path/to/diagram.png]";
// File is extracted and sent back through channelTroubleshooting
For detailed troubleshooting of agent-related issues, see TROUBLESHOOTING.md.
Quick reference:
- Agent not found → Check:
zoobot agent list - Wrong agent responding → Verify routing:
@agent_id message(with space) - Conversation not resetting → Send message after:
zoobot agent reset <id> - CLI not found → Install Claude Code or Codex CLI
- Workspace issues → Check:
cat .zoobot/settings.json | jq '.workspace' - Templates not copying → Run:
zoobot setup
Implementation Details
Code Structure
Queue Processor (src/queue-processor.ts):
getSettings()- Loads settings from JSONgetAgents()- Returns agent configurations (checks.agents)parseAgentRouting()- Parses @agent_id prefixprocessMessage()- Main routing and execution logic
Message Interfaces:
interface MessageData {
agent?: string; // Pre-routed agent ID
files?: string[]; // Uploaded file paths
// ...
}
interface ResponseData {
agent?: string; // Which agent handled this
files?: string[]; // Files to send back
// ...
}Agent Directory Structure
Templates:
~/.zoobot/
├── .claude/ # Copied to new agents
├── heartbeat.md # Copied to new agents
└── AGENTS.md # Copied to new agentsAgent State:
<workspace>/
└── {agent_id}/
├── .claude/ # Agent's own config
├── heartbeat.md # Agent's own monitoring
├── AGENTS.md # Agent's own docs
└── reset_flag # Touch to reset conversationState is managed by the CLI itself (claude or codex) through the -c flag and working directory isolation.
Custom Providers
Custom providers let you use any OpenAI or Anthropic-compatible API endpoint (e.g., proxy servers, self-hosted models, OpenRouter) with the existing CLI harnesses.
Configuration
Custom providers are defined in .zoobot/settings.json:
{
"custom_providers": {
"my-proxy": {
"name": "My Proxy",
"harness": "claude",
"base_url": "https://proxy.example.com/v1",
"api_key": "sk-...",
"model": "claude-sonnet-4-6"
}
}
}| Field | Required | Description |
name | Yes | Human-readable display name |
harness | Yes | Which CLI/API path to use: claude, codex, or groq |
base_url | Yes | API endpoint URL |
api_key | Yes | API key for authentication |
model | No | Default model name to pass to the CLI |
Managing Custom Providers
CLI:
zoobot provider list # List custom providers
zoobot provider add # Add interactively
zoobot provider remove my-proxy # Remove a custom providerAPI:
# List
curl http://localhost:3777/api/custom-providers
# Create/update
curl -X PUT http://localhost:3777/api/custom-providers/my-proxy \
-H 'Content-Type: application/json' \
-d '{"name":"My Proxy","harness":"claude","base_url":"https://proxy.example.com/v1","api_key":"sk-...","model":"claude-sonnet-4-6"}'
# Delete
curl -X DELETE http://localhost:3777/api/custom-providers/my-proxyAssigning to Agents
Use the custom:<provider_id> prefix as the agent's provider:
# When adding a new agent (option 4 in provider selection)
zoobot agent add
# Switch an existing agent
zoobot agent provider coder custom:my-proxy
zoobot agent provider coder custom:my-proxy --model gpt-4oOr edit settings.json directly:
{
"agents": {
"coder": {
"name": "Code Assistant",
"provider": "custom:my-proxy",
"model": "claude-sonnet-4-6",
"working_directory": "/Users/me/workspace/coder"
}
}
}How It Works
When an agent with provider: "custom:<id>" is invoked:
- The custom provider config is looked up from
settings.custom_providers - The
harnessfield determines which CLI to run (claudeorcodex) - Environment variables are set based on the harness:
- claude harness:
ANTHROPIC_BASE_URL,ANTHROPIC_AUTH_TOKEN,ANTHROPIC_API_KEY="" - codex harness:
OPENAI_API_KEY,OPENAI_BASE_URL
- claude harness:
- The CLI is invoked with the model name passed through (no alias resolution)
Provider Auth Readiness API
ZooBot now exposes a provider auth readiness endpoint:
curl http://localhost:3777/api/provider-auth-stateThis reports machine-side provider readiness, including OpenAI/Codex login availability:
- whether an OpenAI API key is configured
- whether a base URL is configured
- whether the Codex CLI is installed
- whether
~/.codex/auth.jsonexists - whether the installed Codex CLI supports device auth
OpenAI / Codex setup examples
Device-auth login on the machine:
npm install -g @openai/codex
codex login --device-auth
zoobot provider openai --model gpt-5.3-codexAPI key fallback:
zoobot provider openai --model gpt-5.3-codex --auth-token YOUR_REAL_OPENAI_API_KEYTeams
Teams are named groups of agents that can collaborate by forwarding messages to each other via @teammate mentions in their responses.
How Team Collaboration Works
- User sends
@dev fix the auth bug(wheredevis a team with leadercoder) - Queue processor resolves
@dev→ team → leader agent@coder - Coder's AI responds:
"I fixed the bug in auth.ts. @reviewer please check my changes" - Queue processor scans response, sees
@revieweris a teammate in teamdev - Queue processor calls reviewer with coder's response (prefixed with context)
- Reviewer responds:
"Changes look good, approved!" - Combined response sent to user:
@coder: ... \n---\n @reviewer: ...
The chain ends naturally when an agent responds without mentioning a teammate.
Team Configuration
Teams are stored in ~/.zoobot/settings.json:
{
"teams": {
"dev": {
"name": "Development Team",
"agents": ["coder", "reviewer"],
"leader_agent": "coder"
}
}
}| Field | Description |
name | Human-readable display name |
agents | Array of agent IDs (must exist in .agents) |
leader_agent | Agent that receives @team_id messages first |
Team IDs share the @ routing namespace with agents, so no collisions are allowed.
Managing Teams
CLI Commands:
zoobot team list # List all teams
zoobot team add # Add a new team (interactive)
zoobot team show dev # Show team configuration
zoobot team remove dev # Remove a team
zoobot team add-agent dev reviewer # Add an existing agent to a team
zoobot team remove-agent dev reviewer # Remove an agent from a teamIn-chat Commands:
/team # List all teams
@dev fix the auth bug # Route to team leader
@coder fix the auth bug # Route directly to agent (team context still active)Direct Agent Routing with Teams
When you message an agent directly (e.g., @coder fix this), team context is automatically activated if the agent belongs to a team. This means teammate mentions in the agent's response will still be followed.
Agent AGENTS.md Updates
When an agent is added to a team, its AGENTS.md file is automatically updated with a team collaboration section listing teammates and instructions for using @teammate_id mentions.
Future Enhancements
Potential features for agent management:
- Shared context: Optional shared memory between agents
- Agent scheduling: Time-based or event-based agent activation
- Web dashboard: Visual agent management and monitoring
- Agent analytics: Track usage, performance per agent
- Workspace templates: Pre-configured agent workspaces for common use cases
- Agent migration: Export/import agent configurations
See Also
- README.md - Main project documentation
- Setup wizard:
zoobot setup - Agent CLI:
zoobot agent --help
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 28,693 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository9 other files it gives its agents.
- AGENTS.mdAGENTS.md
- agent-browserSkill
- imagegenSkill
- memorySkill
- scheduleSkill
- send-user-messageSkill
- skill-creatorSkill
- tasksSkill
- zoobot-adminSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

