Skip to main content
OpenLegion is a fleet model — blackboard + pub/sub + handoff (no CEO agent). There is no LLM in the middle deciding what runs next. Agents coordinate through four explicit primitives, all running on the mesh host:
  • Blackboard — durable shared state in SQLite WAL.
  • PubSub — fan-out events.
  • Lanes — per-agent FIFO queues.
  • Handoffs — durable task records routed through MessageRouter.
Templates assemble agents into ready-made rosters. There are no DAG YAML files and no deterministic orchestrator.

Blackboard

A SQLite WAL key-value store with atomic CAS via write_if_version and an audit log that supports undo and archive. Keys are auto-namespaced under projects/{name}/ so fleets in different projects can’t collide. Tools on mesh_tool:
ToolPurpose
write_blackboardCAS-aware write (version arg)
read_blackboardRead a key (returns value + version)
list_blackboardList keys under a glob
watch_blackboardLong-poll for changes
claim_taskCAS-based claim — used internally by handoffs
save_artifactPromote a tool result to a durable artifact
Typical namespaces: tasks/* (handoffs), context/* (shared context), signals/* (one-shot signals), history/* (append-only audit log).

Pub/Sub

Fan-out topic bus. Both publishing and subscribing are permission-gated by can_publish / can_subscribe.
ToolPurpose
publish_eventPublish a payload to a topic
subscribe_eventLong-poll the topic queue
Use pub/sub for fire-and-forget signals (“research is done”, “new lead came in”) rather than work assignment — for work, use handoffs.

Lanes

Each agent has a per-agent FIFO lane on the mesh. Messages routed into a lane wake the agent up; results are forwarded with a MessageOrigin carrying kind / channel / user so the reply can flow back to the requester. Lanes support three modes:
  • followup (default) — append and wake.
  • steer — inject into a busy agent’s loop. Rate-limited to 10 wakeups / 3600s to avoid thrashing.
  • collect — batch messages while the agent is busy; deliver the whole batch when it goes idle.

Handoffs (coordination_tool)

Structured task assignment between agents. All four functions are part of the coordination_tool:
ToolPurpose
hand_offSend a task to another agent (or capability:<name>). TTL 86400s (24h).
check_inboxList inbound handoffs
update_statusUpdate task status (working, blocked, done)
complete_taskMark a task complete and deliver the result
MessageRouter resolves the target — either a literal agent ID or capability:<name> (routes to whichever agent declares that capability). Cross-project routing is blocked when OPENLEGION_PROJECT_SCOPE_MODE=enforce.

V1 vs V2 task records

Handoffs run in one of two backends:
  • V1 — handoff is stored as a blackboard entry at tasks/{agent}/{handoff_id}. Lightweight, no durable record outside the blackboard.
  • V2 — durable task records in a separate table; surface via the openlegion tasks CLI command. Enabled when OPENLEGION_ORCHESTRATION_TASKS_V2=1default ON in v0.1.0.
V2 is the recommended mode. Set the env var to 0 only if you specifically need the old blackboard-backed behavior.

Fleet Templates

Templates are agent rosters — YAML manifests in src/templates/ that the operator can apply to materialize a fleet. There are 13 templates in the engine today:
TemplateComposition
starterSingle general-purpose assistant
contentresearcher + writer (blog / social / email from briefs)
deep-researchscout + analyst (multi-source synthesis with citations)
devteamPM, engineer, reviewer
monitorwatcher + analyst (always-on)
salesresearcher, qualifier, outreach
competitive-intelcompetitor pricing/product tracking
lead-enrichmentlead list research
price-intelligencecrawler + analyst with anti-bot browser
review-opsG2 / Trustpilot / Capterra / App Store / Google reviews + reply drafts
social-listeningReddit / HN / X competitor pain-point monitor
researchgeneral-purpose researcher
opportunity-findergap-scout + evaluator + modeler
Templates use a "{default_model}" placeholder which is substituted at apply time.

apply_template is per-slot, not atomic

fleet_tool (operator-only) exposes list_templates and apply_template. apply_template accepts agent_overrides per-slot — model, instructions (≤12K), soul (≤4K), heartbeat, interface (≤4K). The role is template-fixed and cannot be overridden. Important: apply_template is per-slot and NOT atomic. If the template has 4 slots and slot 3 fails, agents from slots 1 and 2 stay created. You must clean up partially-applied fleets yourself.

MessageOrigin

Every message — chat input from a channel, a handoff, a lane delivery — carries a MessageOrigin Pydantic model with kind / channel / user. Results flow back along the same path: a Telegram message routed to a researcher and then handed off to a writer eventually returns to the original Telegram user, with no extra plumbing required from the agent code.

Coordination at a Glance

NeedUse
Durable shared stateBlackboard (write_blackboard with CAS)
One-shot broadcastPub/Sub (publish_event)
Append-and-wake another agentLane via followup
Interrupt a busy agentLane via steer (rate-limited)
Hand off a task with a result expectationhand_off (V2 durable record)
Spin up a multi-agent fleetfleet_tool.apply_template (operator-only)