---
title: Omniscio priority boost + adaptive E-core delegation
---

# Omniscio priority boost + adaptive E-core delegation

## 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](session-cpu-cap.md) 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. `reserveUiCoreCount` sizes 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` / `SetPriorityClass` failures 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_CLASS` field (the [Session CPU cap](session-cpu-cap.md) flow), not via `SetPriorityClass`. 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's `EfficiencyClass` byte. 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 logs `non-hybrid CPU — adaptive E-core delegation is a no-op` and the sampler never starts. The toggle is safe to leave on across machines.
- **Affinity application.** The Job Object's `BasicLimitInformation.Affinity` field is set with `JOB_OBJECT_LIMIT_AFFINITY`. Affinity composes with the priority class (the [Session CPU cap](session-cpu-cap.md) write) — both can be set simultaneously without trampling each other. See `writeBasicLimits` in [job-object-win32.ts](../../src/main/process/job-object-win32.ts).
- **State machine.** Two states: `ALL_CORES` (default, affinity cleared) and `E_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 `reserveUiCoreCount` setting (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](../../.claude/memory/contracts/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](../../tests/unit/process/priority-boost-noop.test.ts) — verifies `applyAmcPriorityBoost` returns false and records no boosted PIDs on macOS / Linux.
- **Non-Windows no-op + pure hysteresis (adaptive affinity)**: [tests/unit/process/adaptive-affinity.test.ts](../../tests/unit/process/adaptive-affinity.test.ts) — three layers: (1) non-Windows short-circuit, (2) exhaustive `decideNextAffinityState` table proving threshold semantics, (3) injected-topology end-to-end driving `applyJobAffinity` writes 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](../../src/main/process/priority-boost.ts) — `applyAmcPriorityBoost(enabled)`. Win32 `SetPriorityClass` on self + every Electron child via `app.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](../../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-core `pCores`), `decideNextAffinityState(state, input)`. Hybrid topology detection via `GetLogicalProcessorInformationEx`. 5s sampler. Pure decisions exposed for tests.
- [src/main/process/ui-core-pin.ts](../../src/main/process/ui-core-pin.ts) — `applyUiCorePin(enabled, reserveCount)` (Toggle 4). Engage-and-hold: pins every Omniscio pid onto `computeReservedPhysicalCoreMask(...)` via `setProcessAffinityMask` and re-asserts on a 30s timer; releases only on disable / `AMC_DISABLE_UI_CORE_PIN` / Burst-All. No CPU sampling. Driven from `job-governor.ts` right after `applyAdaptiveAffinity` so the core is already agent-free.
- [src/main/process/job-object-win32.ts](../../src/main/process/job-object-win32.ts) — `setJobAffinity(mask | null)` + `setPriorityClassBelowNormal(below)` cooperatively write `BasicLimitInformation` via shared `writeBasicLimits`. Module mirrors `LimitFlags`, `PriorityClass`, `Affinity` so the two writers compose without trampling.
- [src/main/process/job-object.ts](../../src/main/process/job-object.ts) — `applyJobAffinity(mask | null)` cross-platform shim.
- [src/main/index.ts](../../src/main/index.ts) — applies both toggles at startup right after the existing `applyJobResourceLimits()` call.
- [src/main/services/settings-apply.ts](../../src/main/services/settings-apply.ts) — re-applies both live when their settings keys change.
- [src/renderer/src/features/settings/PerformanceSettings.tsx](../../src/renderer/src/features/settings/sections/performance/PerformanceSettings.tsx) — `boost-amc-process-priority` + `session-adaptive-ecore-affinity` entries in `PERFORMANCE_DEFINITIONS`.

## Related

- [Session CPU cap](session-cpu-cap.md) — 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](job-object-orphan-kill.md) — same singleton Job Object that owns every CLI child. The boost does NOT touch it; the affinity write does.
