Cursor Projects coordinator fan-out: size waves from generation_limits
A Cursor coordinator that delegates to subagents can overrun a Sume workspace. Budget new in-flight jobs from generation_limits, not from wave_size_hint.

A coordinator should size each wave of Sume jobs as max(0, concurrency_limit - active_generation_jobs - queued_generation_jobs), capped by queue_capacity_remaining. Cursor Projects (Sep 10, 2026) lets coordinator agents delegate to subagents, so the width of the fan-out is now a coordinator decision.
The Cursor changelog says coordinators share context across cloud and local, and can be triggered by Slack, schedules and PR streams.
The numbers to read
Generation submit responses include a generation_limits snapshot when Sume can compute one. These fields drive the budget.
| Field | Meaning |
|---|---|
| concurrency_limit | Effective maximum jobs in processing for the workspace. |
| active_generation_jobs | Jobs currently processing. |
| queued_generation_jobs | Jobs currently queued. |
| queue_capacity_remaining | Queue budget plus idle processing seats before queue_full. |
| wave_size_hint | Submission-wave hint only; never a concurrency limit. |
Worked examples from the docs
With concurrency_limit: 100, queued_jobs_limit: 500 and nothing running, queue_capacity_remaining is 600 and wave_size_hint is 450. The workspace is set to 100, so at most 100 new in-flight jobs fit in that snapshot. The 450 is only a hint that includes queue slots.
With 30 jobs processing and 10 queued, the new in-flight budget is 60. At zero headroom, wait and refresh the snapshot before submitting more.
A helper for the coordinator
This function turns a generation_limits object into a number of jobs the coordinator may start now. Count each newly submitted job against the budget until the next live snapshot.
def new_inflight_budget(limits: dict) -> int:
concurrency = int(limits.get("concurrency_limit", 0))
active = int(limits.get("active_generation_jobs", 0))
queued = int(limits.get("queued_generation_jobs", 0))
remaining = int(limits.get("queue_capacity_remaining", 0))
return min(max(0, concurrency - active - queued), remaining)
limits = {
"concurrency_limit": 100,
"active_generation_jobs": 30,
"queued_generation_jobs": 10,
"queue_capacity_remaining": 560,
}
print(new_inflight_budget(limits)) # 60
Rules for the subagents
- Each subagent submits with its own stable
idempotency_key, so a retry returns the original job. - A
queuedjob is normal. Subagents must not resubmit because a job is not yet processing. - On
429 queue_full, stop adding work, wait for jobs to finish, cancel queued jobs that are no longer needed, then retry with the same key. - Return job ids to the coordinator, which waits on batches of up to 20 with
jobs_wait.
Triggers need caps
Because a schedule or a Slack message can start a coordinator without a person present, cap the work in the arguments. max_spend_usd is enforced only when provided, and dry_run=true previews cost without a job. Use generation_admission_preview before an expensive burst.
If a reviewer only reads outputs, give it a read-only OAuth session. Paid tools return insufficient_scope without mcp:write.
Sources
Related posts
More in Agents
- Parallel tool calls on a voice agent: one idempotency key each
ElevenLabs agents default enable_parallel_tool_calls to true. If tools start paid jobs, give each call its own key and wait on all job ids in one batch.
- OpenAI Dots x Runway: brief a dot, it plans shots. The Sume loop
Runway's Oct 1 changelog lists OpenAI Dots x Runway for all plans: brief a dot, it plans shots, Runway shoots. The same loop with Sume MCP tools.
- Run the Sume video agent from your backend with Agent Completions
POST /v1/agent/completions runs the same agent as the Sume Agents chat, with tools and media generation, and returns an async run receipt you poll or webhook.
- Safe automation for AI agents that call paid APIs
Keep agents read-only by default, keep secrets out of logs, and on hosted MCP send an idempotency_key, preview with dry_run, and cap with max_spend_usd.
Written by Sume