Omniscio documentation
Browse all documentation
  1. Getting Started13
  2. Sessions & Agents121
  3. Inbox & Notifications65
  4. Projects & Tasks95
  5. Automation & Scheduling82
  6. Knowledge & Memory26
  7. AI Features66
  8. Integrations101
  9. Plugins & Marketplace34
  10. Cloud & Teams57
  11. Settings & Customization62
  12. Account & Billing28
  13. Troubleshooting86
  14. CLI & API Reference24
  15. Legal & Policies4
  16. Uncategorised17

Admission control (why heavy agent work waits and you never do)

When Omniscio is doing a lot at once — several agents building, searching, installing and starting sessions — a set of machine-wide gates holds the heaviest of that work back so the app stays responsive. Every gate is bounded and fails open, so a job is delayed at worst and then runs anyway; it is never blocked indefinitely. The trade is deliberate and one-directional: slow the agents, never the user.

What it is

Admission control is not one feature — it is a family of gates, each guarding a different way a burst of work can hurt the machine. The ones that matter to you:

  • Heavy-job broker — caps how many heavy background job-trees (builds, tests, big installs) start at once, widening the spacing between starts as the CPU heats up.
  • Disk-pressure and RAM-floor holds — hold new heavy admissions during a disk storm or when memory is collapsing, so the machine drains instead of tipping over.
  • Search admission — thread-caps and gates an agent's rg/grep walks, and batches the find -exec shape that would otherwise fork-bomb the box.
  • Git admission — a light pool caps an agent's shell git walks and the app's own git polls while the machine is loaded.
  • Spawn admission — paces agent package-manager tree-starts (npm/npx/pnpm) and programmatic session spawns box-wide.
  • Dependency installs — an install takes a turn in a shared slot, so only one process writes the package store at a time; if it cannot win the slot inside its window it is refused and can be retried, never run beside another store writer.

Every one of those is fail-open and kill-switched: under a fault, or with its switch set, the gate steps aside and the work runs unpaced. A gate here can only ever delay work — it never skips a check, never weakens a test, and never turns a pass into a fail.

Where to find it

  • Settings → Performance carries the dials you can actually change: the spacing applied to session starts when many come back at once, and the wait between automation-created sessions.
  • The governance control screen (npm run perf:control, GET /perf/control, and the Performance Monitor panel) is where you see every gate at once — its counters, its coverage and its kill-switch name. That surface is documented in full on Governance control and triage.
  • There is no per-gate on/off screen. Each gate's escape hatch is a named environment switch read through the governor-switch helper, and the control screen prints the name of the one you would need.

How it behaves

Bounded waits, tiered on purpose. A lightweight interactive admit (an agent's search or git walk) must never look hung, so it waits only seconds; a heavy queued job (a build behind other builds) legitimately queues for tens of minutes. The tiers are declared in one place so a new gate references its tier rather than copying a bare number: 20 s for interactive admits, 90 s for a nested sub-cap inside an admission the caller already holds, 10 min for the broker, 30 min for heavy queued work, 45 min for the build queue, and a 5 s process-start tier for the spawn-pacing round trip.

The whole local phase is capped too. Individually-bounded caps are not enough on their own, because one run traverses several of them in sequence and nothing bounded their sum against the run's own ceiling — measured, that is how runs spent their entire ceiling queueing locally and returned no verdict at all. So a run now arms a pre-dispatch phase budget: one absolute deadline covering roughly half the run's ceiling, which every admission wait clamps to. Once it is spent, a wait becomes zero and the caller lands on its existing fail-open path and goes and does the work.

Nothing here can make things worse. The phase budget can only ever shorten a wait, never lengthen one, so it cannot introduce a hang; its worst case is the pre-existing fail-open the pools already take on timeout. And the gates for your own input are held to a hard rule — the focused session's grants are released above the mode branch and above the token bucket, so a non-zero "user interactive held" reading means a change stopped releasing that class, which is a violation rather than tuning.

It is deliberately observable rather than silent. The control screen renders not-counted, unproven and unknown instead of a reassuring zero, because a counter that moves proves a gate is reached, and only a hold or a refusal proves it acts.

For agents

This page covers the live admission gates. The inventory heading "Box Reliability / Admission Control" is a machine-wide subject with no single screen; the nearest surfaces are the control screen (perf-control.md) and the severe-lag dial (severe-lag-background-pacing.md), neither of which documents what the gates do — that is what this page is for. Do not map this subject to heavy-job-pacing.md: that page documents a retired system and says so in its own title. Pointing a live subject at a retired page fakes coverage.

Code: the timeout tiers are declared once in scripts/lib/admit-timeouts.mjs (INTERACTIVE_ADMIT_TIMEOUT_MS, SUBCAP_ADMIT_TIMEOUT_MS, BROKER_QUEUE_TIMEOUT_MS, HEAVY_QUEUE_TIMEOUT_MS, BUILD_QUEUE_TIMEOUT_MS, PROCESS_START_ADMIT_TIMEOUT_MS, INSTALL_ADMISSION_DEADLINE_MS) — never re-derive a cap by hand. The pre-dispatch budget is scripts/lib/admission-budget.mjs (armAdmissionBudget, PRE_DISPATCH_BUDGET_FRACTION = 0.5, ADMISSION_DEADLINE_ENV, kill switch AMC_DISABLE_ADMISSION_BUDGET). In src/main a governor is read through governorSwitch(id, role) from src/main/utils/governor-switch.ts — never a raw process.env.AMC_* — and the counters live in src/main/utils/governor-counters.ts. The family's contract is agent-load-governance-contract.md; the control surface's own invariants are in perf-control.md.

Related

Last verified 2026-10-06