A flight is a Markdown document that defines a directed acyclic graph (DAG) of agent tasks. Each H2 section is an agent with a prompt, dependencies, and optional configuration. A pilot agent reads the flight and orchestrates the sub-agents.
Structure
A flight is plain Markdown:
- H1 — the flight name
- H2 — each agent’s slug (unique within the flight)
- Blockquote lines (
> key: value) — agent metadata (persona, dependencies, gates)
- Body text — the agent’s task prompt
Dependencies
Two kinds of transitions connect agents:
needs — the downstream agent starts after the upstream completes. New branch, new VM, no inherited conversation context. Multiple dependencies are comma-separated — all must complete before the dependent starts.
continues — the downstream agent sends a follow-up to the upstream on the same branch and VM. Full conversation context is preserved. This is a 1:1 relationship.
needs and continues are mutually exclusive. An agent can have one or the other, not both.
| Directive | Description |
|---|
persona | Agent persona to use |
model | Model override |
needs | Upstream agents that must complete first |
continues | Upstream agent to send a follow-up to (same context) |
gate | Completion criteria: ci, review, approve, merge |
branch | Explicit branch name (auto-generated if omitted) |
each | Collection description for fanout (one agent per item) |
out | Expected output: pr, push, respond, or freeform |
Fanout
The each directive creates a template agent that the pilot expands into one instance per item. The {} placeholder in the prompt is replaced with each item. When another agent needs an each agent, all expanded instances must complete.
Gates
Gates block downstream agents until conditions are met — CI checks passing, a review agent approving the PR, human approval, or the PR being merged.
Event triggers
Flights stored in the catalog can include YAML frontmatter with on: triggers — issue_opened, pr_opened, pr_labeled, push, schedule (cron), and ci_failure. When a matching event arrives, the platform spawns the flight automatically. See the flight reference for all frontmatter fields and trigger types.
Every agent a flight spawns is automatically tagged with flight-<name> — a flight named deploy tags its agents flight-deploy — so you can group and filter a flight’s runs on the dashboard. Add your own tags with a tags: frontmatter list; they apply to the flight’s agents alongside the automatic tag. Tag names are DNS-label slugs ([a-z0-9][a-z0-9-]{0,62}); the platform creates any that don’t yet exist, and rejects a flight whose name is too long to form a valid flight-<name> tag. See tags.
---
workspace: default
tags:
- release-blocker
- team-infra
---
Daemon vs. standard flights
By default, a triggered flight spawns a fresh instance every time it fires. The pilot agent and any sub-agents do their work, then the VM is reclaimed when idle. The next trigger spawns a brand new instance with no inherited state.
A daemon flight flips that model. Setting daemon: true in the frontmatter makes the flight a singleton: one persistent pilot agent for the lifetime of the flight. Events arriving while the daemon is running are delivered as follow-ups to the same agent on the same branch and VM, so the daemon can keep state between events. When there’s nothing to process, the agent sleeps instead of terminating, and wakes up when the next event arrives.
| Behavior | Standard flight | Daemon flight |
|---|
| Instance per trigger | One new agent per event (subject to max_concurrent) | Singleton, one agent for the lifetime of the flight |
| Idle behavior | Agent terminates after 1 minute idle | Agent sleeps until the next event |
| Context between events | None, fresh branch and VM per instance | Preserved, same branch and VM across events |
| Frontmatter | daemon: false (or omitted) | daemon: true |
service_profile | Required only when the flight has triggers | Always required |
Reach for a daemon when serial processing matters, or when accumulated context between events is valuable. The merge queue daemon below is a canonical example: it processes one ready-to-merge PR at a time, in order, and sleeps between events instead of spinning up a fresh agent for each one.
---
workspace: murmuration
service_profile: default
daemon: true
on:
pr_labeled:
repos: [https://github.com/prassoai/murmuration]
labels: [ready-to-merge]
---
# Merge Queue Daemon
You manage the PR merge queue. Process one PR at a time.
When a PR arrives (approved + labeled `ready-to-merge`):
1. If the PR has merge conflicts, signal the original agent to rebase onto main. Wait for the rebase to complete.
2. Run DiscoverChecks to verify CI is green on the rebased HEAD.
3. Squash-merge the PR.
4. Monitor the merge commit's check run to confirm CI passes on main.
5. Check deployment logs to confirm the change deployed successfully.
6. Kill the original agent now that its PR has landed.
When idle (no PRs queued), sleep until the next `pr_labeled` event arrives.
If a daemon ever crashes or is killed, the next matching event spawns a fresh instance. Daemons recover on the next trigger, not mid-execution.
Running and storing flights
Run a flight with the --flight flag on murmur spawn. Store flights in the catalog with murmur set flight for reuse and event-triggered execution. See the multi-agent orchestration guide for a full walkthrough.