- Blackboard — durable shared state in SQLite WAL.
- PubSub — fan-out events.
- Lanes — per-agent FIFO queues.
- Handoffs — durable task records routed through
MessageRouter.
Blackboard
A SQLite WAL key-value store with atomic CAS viawrite_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:
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 bycan_publish / can_subscribe.
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 aMessageOrigin 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:
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 tasksCLI command. Enabled whenOPENLEGION_ORCHESTRATION_TASKS_V2=1— default ON in v0.1.0.
0 only if you specifically need the old blackboard-backed behavior.
Fleet Templates
Templates are agent rosters — YAML manifests insrc/templates/ that the operator can apply to materialize a fleet. There are 13 templates in the engine today:
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 aMessageOrigin 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.
