Agent work queue

Outcome cc-realtime-queue (Eric 2026-10-06): org owners see and reorder what their org's agents work on next, live, and the agents follow that order.

What it is

One row per queued ticket of an org (agent_work_queue, migration 10880). Agents enqueue tickets; owners and admins reorder, pin, pause and resume them in Operations > Agent queue; agents read the order before launching their next item. Every change is audited (agent_work_queue_audit) and wakes the org's Operations stream, so every open Operations page re-reads within about a second (500 ms coalescer + one snapshot read), with no reload.

Kill switch: platform setting agentQueue.enabled (default on). Off: every queue route returns 404, the MCP tools are not registered, the panel renders nothing.

Order rule (one implementation, packages/shared/src/agent-queue.ts)

  1. Pinned items first, then by rank ascending (ranks are dense 1..n per org).
  2. Next = the first item in that order that is not paused, not blocked, and whose ticket is not closed or archived.
  3. A paused item keeps its place; it is never next.

Status rule (liveness)

An in-progress ticket reads Working only while its newest liveness proof is at most 5 minutes old, Stalled? up to 15 minutes, otherwise Queued (never "working"). Proofs are the shared work-liveness proofs (packages/shared/src/work-liveness.ts, route apps/api/src/modules/work-liveness/routes.ts): boxes post process/transcript/commit proofs once a minute; ticket comments or updates by the item's agent key count too. Why 5 minutes: boxes publish every 60 s, so 5 minutes tolerates four lost or late batches (network blip, a box under load, a long tool call with no log growth) before the label changes, while still dropping a dead agent to Stalled? within 5 minutes and to Queued within 15. A shorter window (e.g. 2 minutes) would flip a healthy agent to Stalled? on a single late batch; a longer one lets a dead agent read Working for most of a quarter hour. (Rationale, not a measurement: no flapping data has been collected yet.)

Who may do what

CallerRead queue / nextEnqueueReorder / pin / pauseRemoveAudit
Owner/admin (signed-in person; reorder/pin/pause and audit refuse every key and user token)yesyesyesyesyes
Member (person)yes (projects they can see)yesno (403)nono
Bot API key of the orgyesyesno (not on the key allow-list, and refused again in the handler)only items it enqueuedno
Person-scoped key, other org403 / 404

The order is a person's decision: an agent cannot promote its own work over what its owner chose.

API

  • GET /v1/orgs/{orgId}/agent-queue -> { orgId, version, canReorder, items[], nextIssueId, generatedAt }
  • GET /v1/orgs/{orgId}/agent-queue/next -> { next | null, paused: issueId[], version }
  • POST /v1/orgs/{orgId}/agent-queue/items { issueId, worker? } -> 201 created / 200 already queued (keeps its place)
  • PATCH /v1/orgs/{orgId}/agent-queue { ifVersion?, move?: { issueId, to: top|up|down|bottom }, order?: issueId[], items?: [{ issueId, pinned?, paused? }] } move (what the Operations panel sends) moves ONE item relative to its neighbours in the caller's view, within its pin group; only that item and the visible items it passes change place. order moves the listed ids to the front of the caller's view in that order; the caller's other items keep their relative order behind them. move and order together are 400. Hidden items never move: a reorder writes the caller's items back only into the places they already held, so an admin with staffed-only project access cannot push an item they cannot see up or down (owner order [H, a, b, c], that admin sees [a, b, c] and moves a down: result [H, b, a, c]). A stale ifVersion is 409 and changes nothing. Any id not in this org's queue, or in a project the caller cannot see, is 404 for the whole patch.
  • DELETE /v1/orgs/{orgId}/agent-queue/items/{issueId} -> 204
  • GET /v1/orgs/{orgId}/agent-queue/audit (owners/admins)

MCP (bot keys): agent_queue_next, agent_queue_list, agent_queue_enqueue. No reorder tool, on purpose.

Contract every agent follows

Before launching any new work item an agent (orchestrator dag-run, QA Commander stage runner, persona job runner):

  1. calls GET .../agent-queue/next (or agent_queue_next) with its org bot key;
  2. launches only next.issueId; if next is null it launches nothing and retries on its normal tick;
  3. re-reads right before the launch side effect (a pause that lands between pick and launch must win);
  4. publishes liveness proofs for what it runs (POST /v1/orgs/{orgId}/work-liveness, once a minute);
  5. removes the item (DELETE) or closes the ticket when the work is done.

If the queue route is unreachable the agent falls back to its own local order and says so in its log; it never treats an unreachable queue as "no pauses". The harness side of this contract is lane harness-queue-sync (agent-rules harness/queue-sync/).

  • API reference: /v1/openapi.json.
  • MCP tools: tool reference.
  • Runbook: working with people.

We use essential cookies to keep you signed in. See our Privacy Policy for details.