You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Optional cap on unsettled threads (a WIP limit for agent work)
#20038
With agents, starting new work is nearly free, so it is easy to end up with a dozen unsettled threads and a brain fried from switching between them. Settling and auto-settle help clean up afterwards, but nothing helps me stop starting things. Kanban boards solve this with a WIP limit on a swim lane: you can't pull in new work until something leaves the lane.
Proposal
An opt-in cap on unsettled threads. When it is on and I'm at the cap, starting a new thread is blocked until I settle (or archive) something.
Settings (shared server settings next to auto-settle, in Settings → General on web/desktop and Settings → Thread behavior on mobile):
unsettledThreadLimit: a number, or off. Off by default, so nothing changes for anyone who doesn't turn it on.
Count snoozed threads: on by default. Snoozed work is still unsettled work; turning this off lets snoozing free a slot.
Count across all environments: off by default (each environment counts its own threads).
What counts: threads that are not settled, archived, or deleted. Subagent child threads don't count (they are already hidden from the sidebar). Pinned and working threads count.
What is gated: only starting new work. That covers sending from a new-thread draft, forks, multi-model fan-out, "implement plan in new thread", and agent/MCP thread creation (t3_thread_launch, create_threads). Batches are all-or-nothing.
What is not gated: un-settling, waking, un-archiving, or replying to an existing thread. Blocking those would be hostile and would make the cap a one-way door. Reopening old work can take you over the cap; you just can't start anything new until you're back under it.
Exempt: threads the server starts on its own (scheduled tasks, the welcome thread, imports). A scheduled task should not silently fail because I'm at my cap.
Visibility: when a cap is set, the Active section header shows a quiet 6 / 8. The new-thread draft tells me I'm at the cap before I write a prompt and offers a way to settle a thread. If the server rejects a send anyway (e.g. another device raced it), the draft is kept.
How it would work
Enforcement is on the server, in one admission check on the thread-launch / thread.create / thread.fork paths, next to the existing provider-enabled check. It returns a typed error carrying { limit, count }, so web, mobile, and agents all get the same message. The check and the create are serialized, so two simultaneous sends can't both slip under the cap. Command-receipt replays skip the check, so dispatch stays idempotent.
The count is a single COUNT(*) on the thread projection. It runs only when the cap is on and only at thread start. With snoozed threads excluded, it reuses the server's existing snooze derivation, so it matches the sidebar.
All-environments mode: each server still enforces the cap on its own count. On top of that, web and mobile add up the unsettled threads across connected environments, using the thread data they already have, and block new drafts at the total. Known limitation: an agent on one environment can't see another environment's threads, and offline environments aren't counted. I'd document this rather than build coordination between servers.
Gated behind a new environment capability, so clients hide the setting on older servers.
Scope
No per-project caps, no per-thread exemptions, no "start anyway" override (raise the setting instead), and no enforcement on reopening existing threads.
If the direction and scope look right, I'd like to implement this as a single PR covering contracts, server, web/desktop, mobile, and the thread-sidebar user doc, with focused server tests.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Problem
With agents, starting new work is nearly free, so it is easy to end up with a dozen unsettled threads and a brain fried from switching between them. Settling and auto-settle help clean up afterwards, but nothing helps me stop starting things. Kanban boards solve this with a WIP limit on a swim lane: you can't pull in new work until something leaves the lane.
Proposal
An opt-in cap on unsettled threads. When it is on and I'm at the cap, starting a new thread is blocked until I settle (or archive) something.
Settings (shared server settings next to auto-settle, in Settings → General on web/desktop and Settings → Thread behavior on mobile):
unsettledThreadLimit: a number, or off. Off by default, so nothing changes for anyone who doesn't turn it on.What counts: threads that are not settled, archived, or deleted. Subagent child threads don't count (they are already hidden from the sidebar). Pinned and working threads count.
What is gated: only starting new work. That covers sending from a new-thread draft, forks, multi-model fan-out, "implement plan in new thread", and agent/MCP thread creation (
t3_thread_launch,create_threads). Batches are all-or-nothing.What is not gated: un-settling, waking, un-archiving, or replying to an existing thread. Blocking those would be hostile and would make the cap a one-way door. Reopening old work can take you over the cap; you just can't start anything new until you're back under it.
Exempt: threads the server starts on its own (scheduled tasks, the welcome thread, imports). A scheduled task should not silently fail because I'm at my cap.
Visibility: when a cap is set, the Active section header shows a quiet
6 / 8. The new-thread draft tells me I'm at the cap before I write a prompt and offers a way to settle a thread. If the server rejects a send anyway (e.g. another device raced it), the draft is kept.How it would work
thread.create/thread.forkpaths, next to the existing provider-enabled check. It returns a typed error carrying{ limit, count }, so web, mobile, and agents all get the same message. The check and the create are serialized, so two simultaneous sends can't both slip under the cap. Command-receipt replays skip the check, so dispatch stays idempotent.COUNT(*)on the thread projection. It runs only when the cap is on and only at thread start. With snoozed threads excluded, it reuses the server's existing snooze derivation, so it matches the sidebar.Scope
No per-project caps, no per-thread exemptions, no "start anyway" override (raise the setting instead), and no enforcement on reopening existing threads.
If the direction and scope look right, I'd like to implement this as a single PR covering contracts, server, web/desktop, mobile, and the thread-sidebar user doc, with focused server tests.
All reactions