Skip to content

The agent protocol

ovld protocol is the authoritative interface between an agent and Overlord. The same operations are available from the CLI, the hosted API, and the MCP surface — drift between them is treated as a bug. This page is the lifecycle you follow while executing a mission.

attach ──► update / heartbeat ──► (ask, if blocked) ──► deliver
│ (repeat) │
└── begins a session, returns full context └── ends the session,
moves objective to
complete, mission
to review

Mode 1 — launched onto a mission. The prompt already contains a mission id or says the session was started by Overlord. Attach immediately and begin the objective.

Mode 2 — asked from chat to use Overlord. A normal conversation where the user asks you to create, inspect, or run Overlord work. Create or inspect, and only attach when the user explicitly says to execute.

Every ovld protocol subcommand that takes --mission-id also takes --objective-id (an objective UUID, or a display id such as coo:312.k7xm).

An objective display id already names its mission — coo:312.k7xm contains coo:312 — so --mission-id is optional whenever you pass one:

Terminal window
ovld protocol update --objective-id coo:312.k7xm --summary "Refactored the parser."
ovld protocol deliver --objective-id coo:312.k7xm --summary "Done."

Reach for the objective form when reconnecting to a mission that is running more than one objective. There, the mission id no longer identifies a unit of work, and commands that rediscover “the active objective” (attach, load-context, connect) return ambiguous_active_objective until you name one.

An objective UUID carries no parent mission, so pass --mission-id alongside it.

The CLI fills --objective-id in from OVERLORD_OBJECTIVE_ID on session-scoped subcommands, so a launched agent rarely types it. Two commands never inherit it: update-objective, where the id names the objective being changed, and discuss-objective, which wants a draft rather than the objective already executing.

These protocol commands take --objective-id (UUID or display id) as their primary argument. A display id is enough on its own:

Terminal window
ovld protocol launch-objective --objective-id coo:312.k7xm --agent claude
ovld protocol list-deliveries --objective-id coo:312.k7xm
ovld protocol queue-objective --objective-id coo:312.k7xm
ovld protocol dequeue-objective --objective-id coo:312.k7xm
ovld protocol update-objective --objective-id coo:312.k7xm --no-auto-advance
  • launch-objective queues a normal execution request for a runner. It does not attach the calling agent. Required: --objective-id, --agent. Optional: --model, --reasoning-effort, --execution-target-id.
  • list-deliveries returns one mission’s newest-first normalized deliveries (summary, verification, follow-up notes, delivery-report evidence — never raw payload JSON). A display id supplies the mission.
  • queue-objective adds or moves the objective in the project’s Run Queue (delivery-driven sequencing, not a direct launch). Optional --queue, --after (queued entry, objective UUID, or display id), --front, and one-based --position; choose at most one placement flag.
  • dequeue-objective removes it from the queue. Already-unqueued objectives return { removed: false }.
  • retry-queue-entry retries one held entry: it clears the hold and resets the attempt budget so the dispatcher tries again on the next tick. Address it with --objective-id or --entry; an entry already dispatched or running is refused.
  • run-queue reads every live queue and entry from --project-id, --objective-id, or --mission-id, optionally narrowed with --queue.
  • reorder-run-queue atomically replaces one queue’s complete entry order; every live entry is required exactly once and running/dispatched entries cannot move.
  • create-run-queue, update-run-queue, delete-run-queue, and reorder-project-run-queues manage queue definitions. New queues start paused; explicitly resume one or directly launch a queued objective to start it. Queue-definition operations require project:update; entry operations require execution_request:create.
  • reorder-future-objectives takes --mission-id and --ordered-objective-ids-json with every future objective UUID in the desired order. Display ids are not accepted there.

Hosted MCP exposes the same operations as overlord_launch_objective, overlord_list_deliveries, overlord_list_run_queues, overlord_reorder_run_queue, overlord_queue_objective (remove: true to dequeue), overlord_manage_run_queue, and overlord_reorder_future_objectives.

Terminal window
ovld protocol attach --mission-id coo:312 --objective-id coo:312.k7xm
ovld protocol attach --objective-id coo:312.k7xm

Pass --objective-id when you already know which objective to execute — attach will not rediscover another one. Runner launches export OVERLORD_OBJECTIVE_ID and the CLI forwards it automatically. Mission-only attach still selects the current active objective, as long as only one is active.

The response prints JSON containing session.sessionKey. The CLI also persists that key for the working directory, so later ovld protocol commands resolve it without --session-key. If auto-resolution fails, pass --session-key <sessionKey> explicitly on every call.

The attach payload gives you everything a fresh agent needs to continue without reading prior chat:

  • objective — the current task body is in objective.objective. Treat it as authoritative for the goal, constraints, and delivery target.
  • previousObjectives / futureObjectives — completed and upcoming steps.
  • history, artifacts, attachments, sharedState — structured context.
  • projectResources — the project’s logical resources resolved for the execution target, each with a resourceKey, path, and state. When a project spans repositories, siblings are read-only context unless a future objective launches in them.
  • agentInstructions — concise workflow guidance and pointers into the structured fields.

attach stores an exact objective/session binding for local connector evidence. It does not read Git state or derive a worktree baseline.

Send a real narrative update when something meaningful happens:

Terminal window
ovld protocol update --session-key <sessionKey> --mission-id coo:312 \
--summary "Implemented the loading state and wired it to the query hook." \
--phase execute

During long mechanical stretches with nothing to narrate, send a liveness heartbeat instead — it updates the session without creating a feed event:

Terminal window
ovld protocol heartbeat --session-key <sessionKey> --mission-id coo:312 \
--phase execute --note "Running the integration suite"

Post at least one update before delivering.

--phase accepts: draft, execute, review, deliver, complete, blocked, cancelled. --event-type accepts: update (default), user_follow_up, alert, discussion_summary, decision. Use decision or discussion_summary to make an important non-file decision visible on the mission.

If you cannot proceed without a human decision, post the question and stop:

Terminal window
ovld protocol ask --session-key <sessionKey> --mission-id coo:312 \
--question "Should the loading state block the whole page or just the panel?"

Do not guess past a genuine fork in requirements. Asking is cheaper than delivering the wrong thing.

Delivery is the concluding step. It stores the summary and optional current annotations, moves the objective to complete, and moves the mission to review.

Terminal window
ovld protocol deliver --session-key <sessionKey> --objective-id coo:312.k7xm \
--summary "Added a loading state to the account page and covered it with a test."

Include optional deliveryReport.agentReport evidence in --payload-json or --payload-file when it helps the reviewer: humanActions, tradeoffsMade, knownRisks, deferredWork, and assumptions. Use empty arrays when there is nothing to report. Human actions must be real user follow-up work — never Git operations or routine testing/review.

Delivery remains immediate: Overlord stores a deterministic report first, then may compose a clearer presentation asynchronously. The original summary is never replaced.

You do not enumerate changed files or inspect git status for delivery. An objective-bound connector callback records only paths directly named by its native edit payload. The CLI synchronizes that local ledger separately from the delivery request. Shell and no-path callbacks record unavailable hook health; they never trigger a worktree scan.

Rationales are optional reviewer annotations, not coverage requirements. When a rationale is useful, each entry uses the canonical fields filePath, label, summary, why, and impact, plus optional hunks containing only header. Do not wrap an entry, use a snake-case alias, or send a file_changes artifact. Unknown keys discard only that advisory entry with a bounded warning; the last valid entry wins when a canonical path is repeated.

Run the local-only preflight first. It drains the exact objective ledger and reports remaining evidence plus bounded hook health; it never scans or classifies the shared worktree:

Terminal window
ovld protocol changes --objective-id coo:312.k7xm

Inline --*-json values are rejected above ~8 KB. For large arrays, stream on stdin with --change-rationales-file - (or --payload-file -). When a summary or question contains backticks, $vars, or other shell-special characters, use --summary-file - / --question-file - with a single-quoted heredoc:

Terminal window
ovld protocol deliver --session-key <sessionKey> --mission-id coo:312 \
--summary-file - <<'EOF'
Refactored `useAccount()` to expose `isLoading`; see $PR for details.
EOF

The working tree may hold changes from other agents, missions, or objectives running in the same checkout. Those are not yours to undo.

If git status shows unrelated dirty paths:

  1. Leave those files intact.
  2. Do not fabricate a rationale for work you didn’t do.
  3. Run ovld protocol changes --objective-id <objective> to inspect only the current objective’s recorded evidence.
  4. Deliver the summary normally. Unrelated worktree state is not a delivery input and cannot block the lifecycle transition.

Delivery ends implementation. Do not keep editing unless the user explicitly asks for follow-up work.

  • Ordinary follow-up questions stay in discussion mode; connector hooks record them as user_follow_up activity — you don’t post those manually.
  • Explicit follow-up implementation on a delivered mission:
    • If a live session still accepts updates: ovld protocol update --begin-follow-up-work --follow-up-intent execution --summary "Beginning follow-up work."
    • If no live session exists: ovld protocol resume-follow-up --mission-id <id> --summary "Beginning follow-up work." and use the returned session key.
  • During follow-up execution, post updates and record change rationales just like the first pass, then deliver again.

Artifacts do not require delivery. Publish a plan, notes, decision, or URL mid-session, then revise it later if needed:

Terminal window
ovld protocol add-artifact \
--mission-id coo:312 \
--type note \
--label "Implementation plan" \
--content-text-file -

Provide --type, --label, and at least one of --content-text / --content-text-file or --external-url. An optional --session-key (auto-injected from the attach cache when present) stamps session/objective provenance; --objective-id does the same when you have no live session, and the session key wins when both are given. Hosted MCP exposes the same call as overlord_add_artifact.

When a later objective or follow-up must revise a plan, notes, or URL artifact created earlier, update that artifact in place instead of delivering a duplicate:

Terminal window
ovld protocol update-artifact \
--mission-id coo:312 \
--artifact-id <artifact-id> \
--expected-revision 2 \
--label "Revised plan" \
--content-text-file -

Use the id and revision from attach / load-context artifacts or ovld mission artifacts. Provide at least one of --label, --content-text / --content-text-file, or --external-url. No session key is required. Stale --expected-revision returns a conflict — refresh and retry. Hosted MCP exposes the same call as overlord_update_artifact.

A mission is a whole feature or goal. An objective is one agent pass — one prompt. Create a new mission for a distinct goal; add objectives to an existing mission for sequential steps toward the same goal:

Terminal window
ovld protocol add-objectives --mission-id coo:312 \
--objectives-json '[{"objective":"Implement the API"},{"objective":"Add CLI docs"}]'
Command Purpose
attach Start a session, return full context. Begin work.
connect Lightweight session without full context assembly. --objective-id pins it.
load-context Read mission context without a session (inspection only). --objective-id selects the objective.
list-deliveries Read one mission’s normalized deliveries. An objective display id supplies the mission.
launch-objective Queue a runner execution. Requires --objective-id (UUID or display id) and --agent.
reorder-future-objectives Replace one mission’s complete future-objective UUID order.
run-queue Read live Run Queues from project, objective, or mission scope.
reorder-run-queue Atomically replace one Run Queue’s complete entry order.
queue-objective Add or move one objective in the Run Queue. Requires --objective-id.
dequeue-objective Remove one objective from the Run Queue. Requires --objective-id.
retry-queue-entry Retry one held Run Queue entry. Requires --objective-id or --entry.
create-run-queue Create a paused queue definition; requires project:update.
update-run-queue Rename, pause, or resume a queue; requires project:update.
delete-run-queue Delete a queue definition; requires project:update.
reorder-project-run-queues Replace the complete queue-definition order; requires project:update.
discover-project Resolve the project from cwd, id, or directory.
search (search-missions alias) Find missions by query, state, project.
statuses List one project’s board columns.
discuss-objective Submit a draft objective for discussion (no session). --objective-id names which draft.
create / prompt Create a draft / create-and-attach a mission.
add-objectives Append ordered objectives to a mission.
update-objective Turn auto-advance on or off, or edit instruction text. Requires --objective-id.
update Post progress, decisions, and optional rationales.
heartbeat Liveness ping, no feed event.
ask Post a blocking question and stop.
deliver Finish: summary, artifacts, rationales, mark complete.
changes Local preflight of changed-file attribution.
resume-follow-up Reopen a delivered objective for follow-up.
read-context / write-context Read or store persistent shared context.
add-artifact Create a mission artifact mid-turn (no delivery required).
update-artifact Revise an existing mission artifact in place.

For the full CLI surface — management commands, the runner, project linking — see the CLI reference. Never invent protocol subcommands; run ovld protocol help when unsure.