orchestratr
concepts

queue and concurrency

how admission control protects the machine, with one FIFO queue, a global cap plus per-provider caps, and the stuck-start guard.

heavy interactive TUIs at 100 times over will take a machine down. orcr protects against that with one queue and two caps. every agent run passes through the same admission path, so no caller can flood the box, whether it is you, a script, an agent spawning agents, or a loop.

every run enqueues

agent run is async, always. the verb's whole job is to validate, persist a durable row, and print <path> <uuid>. the server processes the queue and manages the rest of the lifecycle. every managed agent moves through the same statuses:

queued → starting → working → idle → … → ended

the queue worker promotes strictly FIFO by queue_seq, as an atomic store transaction: queued becomes starting only if the row is still queued and a capacity recount under the write lock shows free slots.

two caps

  • global cap concurrency.max (default 25). this is RAM protection.
  • per-provider caps beneath it, for example claude = 10. any provider name is a valid config key.

promotion needs a free slot in both. a claude agent is promoted only when the global count is under 25 and the claude count is under the claude cap. see configuration for setting the caps.

stuck-start guard

starting means a concurrency slot is claimed and the pane and TUI are being created. if that creation makes no progress (no pane appears, no agent_session pointer is captured) within an internal bound (timings.max_starting, default 2m, reset by each progress marker), the row is marked ended with exit_reason: failed and stops holding its slot. otherwise one hung herdr call could block the whole queue forever.

this is internal plumbing, not a user timeout. the rule is deliberately simple: if the guard expires with no pane recorded, the agent is failed; a pane that shows up later, matched by its launch token, is closed. progress markers are herdr-reported facts only (pane created; agent_session pointer reported). transcript parsing is never a startup requirement. for the actual per-turn timeout, see the explicit --timeout in agent lifecycle and GC.

acting on queued and starting agents

  • wait on a queued agent waits through promotion and its first turn.
  • kill on a queued agent dequeues it, ending it with exit_reason: canceled.
  • kill on a starting agent sets cancel_requested, checked between pipeline steps. once a pane exists, cancellation closes it and ends the row with exit_reason: canceled.

no work was done in either case, which is why both are canceled rather than killed. see status model and completion.

loops have a separate knob

loops do not share the agent queue's caps. a loop's --max-concurrency caps concurrent runs of that loop (default 1), which is a different axis: it limits how many copies of the command run at once, not how many agents each run spawns. the agents a run spawns still pass through the global and per-provider caps like any other agent run. see loops.

On this page