Omniscio priority boost + adaptive E-core delegation
Windows-only Settings → Performance toggles that keep Omniscio's window and your other foreground apps snappy when many Claude sessions saturate the machine: boosting the app's own process priority, delegating sessions to efficient cores under load, and reserving a CPU core for the UI.
What it is
Two related Windows-only performance toggles that keep Omniscio's window and the user's other foreground apps (Chrome, IDE, Zoom) snappy when many Claude CLI sessions are saturating the machine. Live under Settings → Performance, both off by default.
The problem they solve
With the existing Session CPU cap on, Claude CLI children run at BELOW_NORMAL_PRIORITY_CLASS and at a soft combined-rate ceiling. That's enough for the "I have 5 sessions running" case — the scheduler hands the user's browser a slice ahead of any Omniscio child.
It breaks down at "I have 18 sessions running and they're all bursting." Now:
- Omniscio's main + renderer processes are at normal priority, just one notch above the CLI children. Under heavy contention, the kernel still picks Omniscio chronically over individual children but the gap is narrow enough that the UI stutters.
- On hybrid CPUs (Intel 12th-gen+ Alder Lake / Raptor Lake / Core Ultra), the CLI tree is free to land on P-cores. Once the P-cores are pegged, even at below-normal the children compete with Omniscio and Chrome for the fast cores.
The two new toggles address each half of that breakdown.
Where to find it
Where to find the toggles
Settings → Performance section (alphabetical neighbours of the existing CPU cap):
- Boost Omniscio interface priority (Windows only) — master toggle for Above-Normal priority on Omniscio's own Electron processes.
- Push sessions to efficient cores when CPU is high (Windows, hybrid CPUs) — master toggle for adaptive E-core delegation.
- Reserve a CPU core for Omniscio so the window never freezes (Windows, hybrid CPUs) — master toggle for the static UI-core reservation, and the only off switch.
reserveUiCoreCountsizes it (1–8, default 1).
All reapply live without restart — flipping the toggle takes effect immediately.
How it behaves
Toggle 1 — Boost Omniscio interface priority (Windows only)
When this is on, every Omniscio Electron process — main, renderer, GPU, utility, plus any helper renderer Electron later spawns — is set to ABOVE_NORMAL_PRIORITY_CLASS via Win32 SetPriorityClass. Combined with the CLI cap's BELOW_NORMAL, the priority gap widens from one notch (normal vs below-normal) to two (above-normal vs below-normal). The Windows scheduler treats the Omniscio tree like a foreground app even when 18 CLI sessions are at 100% combined CPU.
Behaviour details:
- Follows the foreground (2026-09-16). The boost holds only while an Omniscio window is the foreground window. The moment focus leaves every Omniscio window — you switch to Chrome, say — every Omniscio process, main included, drops to
NORMAL_PRIORITY_CLASS(equal to Chrome) and comes back when you return. The priority writes run in a worker thread and are read back; the main log line[AppTreePriority] blur: … applied N unchanged K …says what the OS actually did. Claude CLI children stay BELOW_NORMAL either way — only the app's own tree follows your focus. - Idempotent. Flipping the toggle on once is enough; flipping off reverts every previously-boosted PID back to
NORMAL_PRIORITY_CLASS. - Refresh timer. A 30s interval re-boosts Omniscio main (cheap) and catches any newly-spawned Electron child (e.g. utility processes for printing, network service, on-demand renderers). Without the refresh, a renderer that crashes and respawns would silently fall back to normal priority. 30s (not a tighter poll) because Electron child churn is rare, so the periodic main-process wakeup +
getAppMetrics()scan stays negligible under heavy session load. - Non-fatal failure mode.
OpenProcess/SetPriorityClassfailures log[PriorityBoost] ...and degrade to no-op; Omniscio continues normally. - Does NOT affect Claude CLI children. Those are managed via the singleton Job Object's
JOB_OBJECT_LIMIT_PRIORITY_CLASSfield (the Session CPU cap flow), not viaSetPriorityClass. The boost only touches Electron's own process tree. - No-op on macOS / Linux.
process.platform !== 'win32'short-circuits before any kernel32 work.
Chrome is unaffected — it stays at the OS-default normal priority. That's intentional: Chrome already has its own scheduler heuristics (PROCESS_INFORMATION_CLASS based on tab visibility / audio playback). Raising Chrome to above-normal would let any tab that's busy push Omniscio's children around. With Omniscio above-normal and Chrome normal, both stay snappy because the CLI children below-normal are the only thing the scheduler can de-prioritize.
Toggle 2 — Push sessions to efficient cores when CPU is high (Windows, hybrid CPUs)
On Intel 12th-gen+ Alder Lake / Raptor Lake / Core Ultra (and equivalent AMD hybrid parts), the CPU has two core types:
- P-cores (performance) — wide, hyperthreaded, fast single-thread, lots of power per core. The cores you want Omniscio's UI and Chrome rendering on.
- E-cores (efficiency) — narrow, non-hyperthreaded, slow single-thread, low power per core. Great for background workloads that don't need single-thread speed.
When this toggle is on, Omniscio monitors host CPU every 5 seconds. When the 5s sample average crosses above 85%, it sets the session Job Object's affinity mask to the E-cores only. Every process in the job — and every future child — is now restricted to E-cores. The P-cores are reserved for Omniscio, Chrome, and anything else the user has open. When CPU drops below 60%, the affinity is released and sessions can use all cores again.
Hysteresis between 60 and 85 prevents flapping when CPU is oscillating around the threshold.
Behaviour details:
- Hybrid detection at boot. A single call to
GetLogicalProcessorInformationEx(RelationProcessorCore, ...)enumerates every core'sEfficiencyClassbyte. If more than one distinct value exists, the lowest is the E-cores, the rest are P-cores. On a non-hybrid CPU (one efficiency class for every core), the module logsnon-hybrid CPU — adaptive E-core delegation is a no-opand the sampler never starts. The toggle is safe to leave on across machines. - Affinity application. The Job Object's
BasicLimitInformation.Affinityfield is set withJOB_OBJECT_LIMIT_AFFINITY. Affinity composes with the priority class (the Session CPU cap write) — both can be set simultaneously without trampling each other. SeewriteBasicLimitsin job-object-win32.ts. - State machine. Two states:
ALL_CORES(default, affinity cleared) andE_CORES_ONLY(affinity = E-core mask). Pure hysteresis decision:decideNextAffinityState(current, pct). - Tuning constants.
HIGH_THRESHOLD = 85,LOW_THRESHOLD = 60,SAMPLE_INTERVAL_MS = 5000. Not configurable — these are the sensible defaults that keep most users happy without exposing a knob that needs explanation. - Non-fatal failure mode. A failed affinity write keeps the state machine at its previous state so the next tick retries.
- Single-group only. Windows Job Object affinity is single-group (max 64 logical CPUs per processor group). Typical desktops are one group; this is fine. If Omniscio ever runs on a NUMA box that's two groups, the affinity write picks the first group's E-cores only — still a safe degradation.
- No-op on macOS / Linux. Same short-circuit as the priority boost.
- No-op when toggle is off. Disable also immediately releases any active affinity constraint back to all cores.
Toggle 3 — Reserve a CPU core for Omniscio so the window never freezes (Windows, hybrid CPUs)
Toggle 2 reacts — it only moves sessions off the P-cores once host CPU is already pegged above 85%. Under an extreme storm (250+ agent processes on an i9-14900K), the window can still be starved off the CPU entirely before the sampler reacts. The user's symptom: clicking Approve on a dialog and nothing happens — the renderer is frozen for seconds (heartbeat-tape verdict STARVED, Omniscio's process getting ~1% CPU), then the dialog "won't disappear." It's pure OS scheduling starvation, not a slow line of Omniscio code.
When this toggle is on, Omniscio permanently reserves one or more full physical P-cores for its own window by setting the session Job Object's affinity to every logical CPU except the reserved P-core's threads. The agents are fenced off the reserved core; every current and future session child inherits the mask. The reserved core is then agent-free, so the OS always has an uncontended fast core to schedule Omniscio's (priority-boosted) window on — and the multi-second freezes go away.
Behaviour details:
- Reserves a FULL physical core. The reserved core is a whole physical P-core (both hyperthreads on a hyperthreaded chip), computed from the per-physical-core topology, so a sibling thread can't quietly contend for it. The reservation picks the highest-indexed P-core (furthest from logical CPU 0, where Windows concentrates kernel/DPC interrupt work) and always leaves the rest of the P-cores in the sessions' pool.
- One core by default (~6%), and sizable. On a 32-thread CPU, reserving one physical P-core hands the sessions 30 of 32 threads — they barely notice. How many cores are reserved is the
reserveUiCoreCountsetting (1–8, default 1); raise it when Omniscio's window, GPU process and helpers together need more than a single core to stay smooth under a heavy swarm. The sessions are never left with fewer than one physical P-core no matter how high you set it, so on a smaller CPU the reservation lands lower than asked —getAdaptiveAffinityStatus()reports the requested and the effective count separately so that is visible rather than silent. - Omniscio is NOT pinned by the reservation. Reservation only fences the agents off the reserved core; Omniscio's own processes keep an all-cores affinity. The former dedicated-core pin was retired after inherited affinity caused severe stalls.
- Composes with Toggle 2. Both behaviors flow through the ONE affinity writer (
applyAdaptiveAffinity), so they never fight over the single Job Object affinity field: the reservation is the released ("all cores") baseline, and the E-core confinement is a subset on top (it already excludes every P-core). With Toggle 2 off, the reservation is applied once statically — no sampler needed, since future spawns inherit the Job Object mask. - Suspended during a CPU burst. A deliberate full run (the global CPU-Burst window) wants the whole machine, so the reservation — like every other session limiter — is lifted while Burst-All is open and restored when it closes.
- Hybrid-only, Windows-only. Requires a hybrid-topology CPU (the per-physical-core P-core split). Silent no-op on non-hybrid CPUs and on macOS / Linux.
Retired dedicated-core pin
The former dedicated UI-core pin is no longer exposed and cannot be activated by a persisted or API-written legacy value. Its schema field remains only so older settings payloads still parse. See ui-core-pin-contract.md.
The three CPU-scheduling toggles (cap, boost, adaptive affinity) compose well:
- Cap on, boost on, adaptive off — pre-hybrid (non-Alder-Lake) machines or users who don't want adaptive behavior. The cap + boost combo is the recommended starting point.
- Cap on, boost on, adaptive on — i7-12700K-class hybrid CPUs. The cap throttles combined-rate, the boost widens scheduler win-rate, and the affinity physically removes children from P-cores while pressure is high. This is the configuration the user is on (2026-05-27).
- Cap off, boost on — for users who don't care about the rate cap but do want a fast UI under contention.
Why these specific defaults
- Off by default for both. They're situational. Users running 1–3 sessions never see the symptoms they fix, and they'd be surprised by their first session running on E-cores only. Discoverable via the Performance section once a user reports "Omniscio feels slow when I have a lot of sessions."
- Above-Normal, not High / Realtime. Above-Normal is the priority class for "important foreground app" — what Windows itself uses for the active-window process when configured for "best performance for programs." High and Realtime are for system services and would starve everything else. Above-Normal is the safe ceiling.
- HIGH_THRESHOLD = 85. Empirically the level at which a 20-logical-core machine (i7-12700K) becomes noticeably less responsive in the Omniscio window. Below this, the kernel scheduler handles the load fine on its own.
- LOW_THRESHOLD = 60. Picked to give a healthy hysteresis band (25 percentage points). Lower would cause flapping during normal usage bursts; higher would keep sessions stuck on E-cores too long after the spike passes.
- 5s sample interval. Long enough to smooth out instantaneous spikes, short enough to react to sustained pressure within ~10s.
For agents
How this is verified
- Non-Windows no-op (priority boost): tests/unit/process/priority-boost-noop.test.ts — verifies
applyAmcPriorityBoostreturns false and records no boosted PIDs on macOS / Linux. - Non-Windows no-op + pure hysteresis (adaptive affinity): tests/unit/process/adaptive-affinity.test.ts — three layers: (1) non-Windows short-circuit, (2) exhaustive
decideNextAffinityStatetable proving threshold semantics, (3) injected-topology end-to-end drivingapplyJobAffinitywrites through every state transition. - Manual smoke (Windows + hybrid CPU): enable both toggles, spawn 18+ sessions, watch Task Manager → Details → CPU column. Omniscio processes should show "Above normal" priority. While sessions are bursting, Omniscio's process row stays at full speed; CLI children compete for E-cores only (visible via Task Manager → CPU graph view, where logical processors 16-19 on an i7-12700K pin first).
Implementation pointers
- src/main/process/priority-boost.ts —
applyAmcPriorityBoost(enabled). Win32SetPriorityClasson self + every Electron child viaapp.getAppMetrics()(filtered to exclude the main process pid). 30s refresh timer catches newly-spawned children. Cross-platform shim no-ops on macOS / Linux. - src/main/process/adaptive-affinity.ts —
applyAdaptiveAffinity(ecore, reserveCount)(the ONE affinity writer for both the E-core sampler AND the UI-core reservation),computeReservedUiCoreMask(topology, count)(pure agents-only-mask math, exposed for tests),getTopology()(now also exposes per-physical-corepCores),decideNextAffinityState(state, input). Hybrid topology detection viaGetLogicalProcessorInformationEx. 5s sampler. Pure decisions exposed for tests. - src/main/process/ui-core-pin.ts —
applyUiCorePin(enabled, reserveCount)(Toggle 4). Engage-and-hold: pins every Omniscio pid ontocomputeReservedPhysicalCoreMask(...)viasetProcessAffinityMaskand re-asserts on a 30s timer; releases only on disable /AMC_DISABLE_UI_CORE_PIN/ Burst-All. No CPU sampling. Driven fromjob-governor.tsright afterapplyAdaptiveAffinityso the core is already agent-free. - src/main/process/job-object-win32.ts —
setJobAffinity(mask | null)+setPriorityClassBelowNormal(below)cooperatively writeBasicLimitInformationvia sharedwriteBasicLimits. Module mirrorsLimitFlags,PriorityClass,Affinityso the two writers compose without trampling. - src/main/process/job-object.ts —
applyJobAffinity(mask | null)cross-platform shim. - src/main/index.ts — applies both toggles at startup right after the existing
applyJobResourceLimits()call. - src/main/services/settings-apply.ts — re-applies both live when their settings keys change.
- src/renderer/src/features/settings/PerformanceSettings.tsx —
boost-amc-process-priority+session-adaptive-ecore-affinityentries inPERFORMANCE_DEFINITIONS.
Related
- Session CPU cap — sibling toggle. The cap throttles the CLI tree; the boost lifts Omniscio's UI above them; adaptive affinity moves the CLI tree off P-cores under load.
- Job Object orphan-kill — same singleton Job Object that owns every CLI child. The boost does NOT touch it; the affinity write does.
Last verified 2026-09-23