Repository navigation
[Feature]: Optional agent-selection policy hook for orchestration worker-start #21747
Description
Problem or use case
orca orchestration worker-start takes --agent and --model as a human decision, made once and then repeated by habit. With several subscriptions renewing on different dates, that decision goes stale within hours: the plan that was the obvious choice this morning is at 90% by the afternoon, while another has just rolled over and its unused window is about to expire.
Today the only ways to react are to remember, or to discover the wall by having a worker fail.
#20512 asks for automatic failover between several accounts of the same provider. The same gap exists one level up, across agents and models:
- Mechanical edits and ordinary implementation do not need the strongest model, and running them on one burns a scarce allowance twenty times faster than a cheap model would. On a percent-bucket plan, model price is the burn multiplier.
- Design, diagnosis, and anything touching auth, migrations or money is worth escalating, but only when there is headroom to escalate into.
- Capacity in a window that resets in three hours is about to be thrown away; capacity in a monthly window is the scarce thing. Spending them in the wrong order wastes the first and exhausts the second.
None of that is Orca's business to decide, and it should not be. But Orca is the only component that knows the accounts, the per-account homes, and the usage.
Proposed solution
An optional policy hook, consulted by worker-start when configured, and ignored entirely when not:
// settings
"orchestration": {
"agentPolicy": "/usr/local/bin/my-router --json"
}Orca writes a JSON object on stdin:
{
"spec": "<task text>",
"worktree": "...",
"repo": "...",
"available": [
{"agent": "codex", "account": "acct_a", "models": ["gpt-6-astra"], "usage": {...}},
{"agent": "claude", "account": "acct_b", "models": ["claude-opus-5"], "usage": {...}}
],
"requested": {"agent": "opencode", "model": null}
}and reads one object back:
{"agent": "codex", "model": "gpt-6-astra", "effort": "high", "reason": "design work, and the weekly window resets in 3h with room left"}Rules that keep it safe:
- No hook configured, non-zero exit, invalid output or a timeout, and
worker-startproceeds exactly as it does today with the requested agent. The hook can only ever refine a default, never block a launch. - The returned
reasonis recorded on the dispatch, sotask-listanddispatch-showexplain after the fact why a worker was started on a given agent. - Same hook consulted on an automatic retry after a rate-limit stall, which is where it composes with [Feature]: Automatic account failover on rate limit for managed Claude/Codex subscription accounts #20512: that issue chooses another account, this one can choose another agent entirely when no account of that provider has room.
Alternatives or additional context
The workaround is a wrapper script that decides and then calls worker-start, which is what I am building now as a standalone tool. It works, but it is strictly worse in two ways: it cannot see Orca's managed per-account state, so it reasons about host-level quota rather than the account the pane will really use, and it is out of the loop on any retry Orca performs internally.
Deliberately not proposed here: Orca shipping a policy of its own. The useful split is that Orca owns the facts and the mechanism, and the user owns the policy, which is also why this is a hook rather than a settings matrix.
Related: #20512 (account failover), #14952 (custom agent binaries for worker-start), #18329 (choosing model and effort at create time).
Activity
karoliang commentedon Sep 21, 2026
Follow-up from implementing the local router: Rightsize #21 records the execution contract needed to make quota-aware admission trustworthy.
Read-only inspection of Orca1.4.205 and upstream
ffb79c71e04e79df08179530f8e7bc3683363e3bfound thatWorkerStartParamshas agent/model/effort but no explicit account reference or prepared-session handle. The structured setup gate waits for repository setup, rather than native-account preparation. Internal account services alone do not let a caller prove which account will consume the task.A small versioned preparation/launch boundary would let the external policy own its decision while Orca owns execution:
The advisory hook proposed here can retain its existing fallback semantics. A caller that has explicitly enabled managed quota admission also needs a strict path: an unverified preparation or account mismatch cannot proceed on another account, and internal retries must not silently spend outside the admitted identity. This can be a separate opt-in contract; no built-in routing policy or credential store is requested.
No worker was launched or installed runtime modified during the inspection. Is there an existing supported preparation boundary that supplies these guarantees, or should this extend the worker-start contract?
naochan3 commentedon Oct 5, 2026
+1, with a user-side perspective and a short field report.
Field report. On Windows (Orca 1.4.220) I run a Claude chat as the coordinator and let it delegate to Codex workers via
orca orchestration worker-start --agent codex --model … --effort …, driven only by a routing table in the repo's instruction file (large implementation →gpt-6-astra, small fixes and image generation →gpt-6.1-sol, design/writing/final judgment → the coordinator itself). It works end to end today: the coordinator picked Codex on its own for a multi-file task, waited forworker_done, reviewed and fixed the result, then released the worker. So the plumbing is there; what is missing is exactly what this issue describes, plus a few things below.What I would add to the proposal
reasonon the dispatch is great. Recording duration, outcome and whether the coordinator had to rework the result next to it would let users (and router authors) check whether a routing rule actually helps, instead of trusting a black box. Today I log this by hand in a markdown table.Quota awareness (the core of this issue) is the gap I hit most: neither the coordinator nor the routing table can see remaining Claude/Codex windows, so routing ignores the one signal that actually changes the right answer during the day.
xiemintech commentedon Oct 10, 2026
Adding a concrete quota-aware orchestration use case for local Claude Code and Codex subscriptions across multiple worktrees:
worker-startand retries. Related: [Feature]: Select the Claude account for headless/agent spawns via CLI (--account / orca account list) #8770 and [Feature]: Automatic account failover on rate limit for managed Claude/Codex subscription accounts #20512.Acceptance case: with Claude account A at 4% remaining in its 5-hour window, a queued task in any worktree is assigned to eligible account B or Codex; if neither has capacity, it stays queued and resumes after a verified reset.
Additional handoff requirement: Orca should be able to continuously refresh a dedicated, machine-managed quota section in the project handoff document, so a replacement coordinator or worker in any worktree can pick up the latest subscription state and scheduling decision. Update it before dispatch/handoff and when quota, account binding, or reset status materially changes. Include provider, opaque account label, each window's remaining %, reset time, observed-at/freshness, current routing/paused state, and the reason for any switch. Mark unavailable or stale measurements explicitly; do not write access tokens, cookies, email addresses, or other credentials. The section should be atomically replaced rather than appended on every poll, to avoid stale entries and noisy file conflicts.
karoliang commentedon Oct 13, 2026
Follow-up from the blocked consumer launch on Orca 1.4.224: external routing accepts the complete repair task and its failure evidence, but the launch cannot prove that the receiving OpenCode worker uses the subscription account whose quota was probed.
MiniMax and GLM are separate provider token-plan accounts; OpenCode is their client. This host currently has no managed OpenCode profile. The CLI supports adding a private OpenCode profile, but registering/selecting one alone does not supply the required receiving-worker receipt. No credentials were changed, worker launched or account gate bypassed during this inspection.
Read-only inspection of upstream source at 4d65146 identifies existing seams to reuse (source main is not installed-runtime proof):
opencode-structured-account-home.tsalready pins a managed profile and resolves its execution-host environment.opencode-launch-model-context.tsprobes a separate temporary server, then stops it. That is useful preflight, but not evidence from the process receiving the task.worker-launch-preferences.tsreports requested/effective model preferences, without the provider-plan identity or task-consumption binding.WorkerStartParamshas no selected-account/prepared-context reference.The narrow missing contract is an opt-in, versioned runtime-owned receipt from the actual receiving process, or a runtime-owned execution channel that proves it delivers the task to that same prepared process/account. It should bind an opaque provider-plan principal matching the external quota probe, effective provider/model/effort, execution-host/process or session incarnation, worktree/cwd, full UTF-8 task hash, and Run/Task/Dispatch. No token export or new routing/scheduling policy is requested.
Missing capability, wrong account, credential rotation, model fallback, changed task or reused/unknown process must refuse before task/model input. Existing-terminal attach must not bypass the check. Lost-ack recovery must discover the same receipt/attempt without replaying the task. Profile selection, requested-settings echo or a separate probe server must not be labelled verified receiving identity.
Could a maintainer identify the supported existing boundary, or an owning source task/PR and target runtime version for this extension? The consumer will keep the launch held until the installed runtime can prove this contract, then perform one bounded source-only retry with unchanged full requirements, failure history and independent review. The advisory policy hook can retain its existing compatibility behavior; this request is specifically the strict account-bound launch path described in the earlier follow-up.
Gabrielgvl commentedon Oct 14, 2026
+1, with a field report from an external router we run in front of
worker-start. It has handled about 245 routes since Oct 9 on 1.4.221.For each task, the router does three things:
account listusage, plus a local cooldown that a worker writes when it hits a 429.Grading and review tasks also exclude the implementer's quota provider.
What we ran into that a hook contract should cover:
worker-startrejects--model(orchestration worker-start: accept --model (and --effort) for the pi and devin agents #26971 / feat(orchestration): support pi and devin worker launch models #27012). So we start the agent in our own terminal and attach it with--terminal. Orca records those terminals as external, andworker-releasekeeps them. They leak unless the caller closes them; we had 100+ idle agent processes before we noticed. A hook that returns a model only helps ifworker-startcan apply that model for every agent.account listentries are sometimes hours old. We treat an entry older than 30 minutes as advisory, and only trust an "exhausted" window that has a future reset time. Please include the observation time for each window in the hook input, as @xiemintech suggests.+1 to recording
reasonon the dispatch. Today we keep our own append-only log of routing decisions because the dispatch carries none.