Agent Orchestration
Overview
OMAR uses a hierarchical agent model. An Executive Assistant (EA) breaks high-level tasks into parallel sub-tasks and spawns worker agents — each agent can in turn spawn its own children, creating arbitrary depth. Every agent drives OMAR through the MCP tool surface delivered by its private omar mcp-server stdio child.
Unified Agent Model
All spawned agents use the same prompt (agent.md). There is no PM/worker distinction — every spawned agent is autonomous: it receives a task, decides whether to do the work itself or spawn sub-agents, and reports completion.
The EA (executive-assistant.md) is special: it acts purely as a dispatcher — it never does work directly, only spawns agents, monitors them, and manages projects. It gets memory context prepended to its prompt.
Agent Lifecycle
User gives task to EA
│
▼
EA registers a project (add_project) and spawns agents (spawn_agent)
│
▼
agent-1 (working) agent-2 (working) agent-3 (idle)
│
▼
Agents schedule_omar_event back to their parent on completion
│
▼
EA aggregates results, calls complete_project when done
Parent-Child Hierarchy
Agents track their parent via ~/.omar/ea/<id>/agent_parents.json. This enables:
- Tree visualization in the TUI (command tree with box-drawing)
- Navigation:
↑/↓moves selection,←/→switches panels,Tabdrills into children,Shift+Tabreturns to parent - Hierarchical status monitoring
Any agent can spawn children, creating arbitrary depth.
EA Protocol
The EA communicates with OMAR exclusively via MCP tool calls. It never does work directly — it only spawns agents, monitors their output, and manages projects. Tool names below are written as the agent sees them in its tool palette (e.g. omar.spawn_agent).
Registering a project
Every spawn requires a project_id, so the EA opens a project before delegating:
omar.add_project({ "name": "Build REST API" })
// → { "project_id": 1, "name": "Build REST API" }
Spawning agents
omar.spawn_agent({
"name": "api",
"task": "Create Express server with /users and /posts endpoints",
"project_id": 1,
"parent": "ea"
})
Monitoring agents
omar.list_agents() // → all agents in this EA, with health
omar.get_agent({ "name": "api" }) // → pane tail + status + parent
omar.get_agent_summary({ "name": "api" }) // → lightweight card view
Sending input to agents
omar.send_input({
"name": "api",
"text": "Also add /comments endpoint",
"enter": true
})
Killing agents
omar.kill_agent({ "name": "api" })
kill_agent flips any Running task row for that agent to Failed and cancels its scheduled events, so the project board never holds orphan rows.
Managing projects
omar.list_projects()
omar.complete_project({ "project_id": 1 }) // blocks while any task is still Running
Agent Context
When spawning agents with a task, OMAR injects the unified agent.md prompt. Each agent is autonomous — it decides whether to do the work itself or spawn sub-agents:
You are an Agent in the OMAR system.
You receive a task from your parent, assess it, and
decide the best way to get it done — either by doing
it yourself or by spawning sub-agents.
YOUR NAME: api
YOUR PARENT: ea
YOUR TASK: Create Express server with /users and /posts endpoints
Agents signal completion by outputting [TASK COMPLETE] followed by a summary, then immediately wake the parent:
omar.schedule_omar_event({
"receiver": "ea",
"payload": "[CHILD COMPLETE] api: Express server with /users and /posts endpoints",
"delay_seconds": 0
})
The parent (the EA, or another agent) sees the message land in its tmux session and aggregates accordingly.
Event-Driven Coordination
OMAR’s scheduler is the single coordination primitive for timed waits. Backend-native wake tools (ScheduleWakeup, TaskReminder, etc.) are denied at the spawn level — agents must use schedule_omar_event so wake-ups appear in the dashboard’s event queue and survive restarts.
One-shot wake-up
omar.schedule_omar_event({
"receiver": "api",
"payload": "Check progress on API implementation",
"delay_seconds": 60
})
Recurring cron-style check-in
omar.schedule_omar_event({
"receiver": "api",
"payload": "Progress check",
"recurring_seconds": 300
})
Events are durable: they’re persisted to ~/.omar/scheduled_events.json and replayed across dashboard restarts. They’re delivered by injecting the payload into the receiver’s tmux session.
Memory Persistence
OMAR maintains state across sessions, scoped per EA:
~/.omar/ea/<id>/memory.md— Snapshot of active projects, agents, and tasks~/.omar/ea/<id>/worker_tasks.json— Map of session name to task description~/.omar/ea/<id>/task_registry.json— Authoritative task records (id, status, history)~/.omar/ea/<id>/agent_parents.json— Parent-child relationships~/.omar/ea/<id>/status/<session>.md— Agent self-reported status~/.omar/manager_notes_ea<id>.md— Free-form EA notes (the EA writes these via shell heredoc)~/.omar/scheduled_events.json— Durable event queue (shared across EAs, scoped byea_id)
On restart, the EA prompt includes the last memory snapshot for continuity, and pending events resume firing on schedule.