7.5 KiB
Multi-Agent Orchestration
Agor supports running multiple AI agents that communicate with each other, coordinate work through a shared task board, and are managed by a hierarchy of specialized roles. This document covers the inter-agent messaging system (btmsg), the task board (bttask), agent roles and system prompts, and the auto-wake scheduler.
Agent Roles (Tier 1 and Tier 2)
Tier 1 — Management Agents
Defined in groups.json under a group's agents[] array. Each management agent gets a full ProjectBox in the UI (converted via agentToProject()). They have role-specific capabilities, tabs, and system prompts.
| Role | Tabs | btmsg Permissions | bttask Permissions | Purpose |
|---|---|---|---|---|
| Manager | Model, Tasks | Full (send, receive, create channels) | Full CRUD | Coordinates work, creates/assigns tasks |
| Architect | Model, Architecture | Send, receive | Read-only + comments | Designs solutions, creates PlantUML diagrams |
| Tester | Model, Selenium, Tests | Send, receive | Read-only + comments | Runs tests, monitors screenshots |
| Reviewer | Model, Tasks | Send, receive | Read + status + comments | Reviews code, manages review queue |
Tier 2 — Project Agents
Regular ProjectConfig entries in groups.json. Each project gets its own Claude session with optional custom context via project.systemPrompt. Standard tabs (Model, Docs, Context, Files, SSH, Memory) but no role-specific tabs.
System Prompt Generation
Tier 1 agents receive auto-generated system prompts built by generateAgentPrompt() in utils/agent-prompts.ts with 7 sections: Identity, Environment, Team, btmsg docs, bttask docs, Custom context, Workflow.
Tier 2 agents receive only the custom context section (if project.systemPrompt is set).
BTMSG_AGENT_ID
Tier 1 agents receive the BTMSG_AGENT_ID environment variable, injected via extra_env in AgentQueryOptions. This flows through 5 layers: TypeScript -> Rust -> NDJSON -> JS runner -> SDK env. The CLI tools (btmsg, bttask) read this variable to identify which agent is sending messages.
Periodic Re-injection
AgentSession runs a 1-hour timer that re-sends the system prompt when the agent is idle, countering LLM context degradation over long sessions.
btmsg — Inter-Agent Messaging
btmsg lets agents communicate with each other via a Rust backend (SQLite), a Python CLI tool, and a Svelte frontend (CommsTab).
Database Schema
The btmsg database (btmsg.db, ~/.local/share/agor/btmsg.db) stores all messaging data:
| Table | Purpose | Key Columns |
|---|---|---|
agents |
Agent registry | id, name, role, project_id, status, created_at |
messages |
All messages | id, sender_id, recipient_id, channel_id, content, read, created_at |
channels |
Named channels | id, name, created_by, created_at |
contacts |
ACL | agent_id, contact_id (bidirectional) |
heartbeats |
Liveness | agent_id, last_heartbeat, status |
dead_letter_queue |
Failed delivery | message_id, reason, created_at |
audit_log |
All operations | id, event_type, agent_id, details, created_at |
CLI Usage (for agents)
btmsg send architect "Please review the auth module design"
btmsg read
btmsg channel create #architecture-decisions
btmsg channel post #review-queue "PR #42 ready for review"
btmsg heartbeat
btmsg agents
Dead Letter Queue
Messages sent to non-existent or offline agents are moved to the dead letter queue instead of being silently dropped.
bttask — Task Board
bttask is a kanban-style task board sharing the same SQLite database as btmsg (btmsg.db).
Task Lifecycle
Backlog -> In Progress -> Review -> Done / Rejected
When a task moves to "Review", the system auto-posts to the #review-queue btmsg channel.
Optimistic Locking
To prevent concurrent updates from corrupting task state, bttask uses a version column:
- Client reads task with current version (e.g., version=3)
- Client sends update with expected version=3
- Server's UPDATE includes
WHERE version = 3 - If another client updated first (version=4), WHERE matches 0 rows -> conflict error
Role-Based Permissions
| Role | List | Create | Update Status | Delete | Comments |
|---|---|---|---|---|---|
| Manager | Yes | Yes | Yes | Yes | Yes |
| Reviewer | Yes | No | Yes (review decisions) | No | Yes |
| Architect | Yes | No | No | No | Yes |
| Tester | Yes | No | No | No | Yes |
| Project (Tier 2) | Yes | No | No | No | Yes |
Review Queue Integration
The Reviewer agent gets special treatment in attention scoring: reviewQueueDepth adds 10 points per review task (capped at 50). ProjectBox polls review_queue_count every 10 seconds for reviewer agents.
Wake Scheduler
The wake scheduler automatically re-activates idle Manager agents when attention-worthy events occur (wake-scheduler.svelte.ts).
Strategies
| Strategy | Behavior | Use Case |
|---|---|---|
| Persistent | Resume prompt to existing session | Long-running managers |
| On-demand | Fresh session | Burst-work managers |
| Smart | On-demand when score exceeds threshold | Avoids waking for minor events |
Wake Signals
| Signal | Weight | Trigger |
|---|---|---|
| AttentionSpike | 1.0 | Project attention score exceeds threshold |
| ContextPressureCluster | 0.9 | Multiple projects >75% context usage |
| BurnRateAnomaly | 0.8 | Cost rate deviates from baseline |
| TaskQueuePressure | 0.7 | Task backlog grows beyond threshold |
| ReviewBacklog | 0.6 | Review queue has pending items |
| PeriodicFloor | 0.1 | Minimum periodic check |
Pure scoring function in wake-scorer.ts (24 tests). Types in types/wake.ts.
Health Monitoring & Attention Scoring
The health store (health.svelte.ts) tracks per-project health with a 5-second tick timer.
Activity States
| State | Meaning | Visual |
|---|---|---|
| Inactive | No agent running | Dim dot |
| Running | Agent actively processing | Green pulse |
| Idle | Agent finished, waiting for input | Gray dot |
| Stalled | No output for >N minutes | Orange pulse |
Stall threshold is configurable per-project (default 15 min, range 5-60, step 5).
Attention Scoring
| Condition | Score |
|---|---|
| Stalled agent | 100 |
| Error state | 90 |
| Context >90% | 80 |
| File conflict | 70 |
| Review queue depth | 10/task, cap 50 |
| Context >75% | 40 |
Pure scoring function in utils/attention-scorer.ts (14 tests).
File Conflict Detection
Two types detected by conflicts.svelte.ts:
- Agent overlap — Two agents in the same worktree write the same file
- External writes — File modified externally (detected via inotify, 2s timing heuristic)
Session Anchors
Session anchors preserve important conversation turns through Claude's context compaction process.
Anchor Types
| Type | Created By | Behavior |
|---|---|---|
| Auto | System (first compaction) | Captures first 3 turns, observation-masked |
| Pinned | User (pin button) | Marks specific turns as important |
| Promoted | User (from pinned) | Re-injectable via system prompt |
Anchor Budget
| Scale | Token Budget | Use Case |
|---|---|---|
| Small | 2,000 | Quick sessions |
| Medium | 6,000 | Default |
| Large | 12,000 | Complex debugging |
| Full | 20,000 | Maximum preservation |
Re-injection flow: anchors.svelte.ts -> anchor-serializer.ts -> AgentPane.startQuery() -> system_prompt -> sidecar -> SDK.