Documentation / Resource Engine

Resource Engine

A desktop shell that understands the machine it runs on, and arbitrates between the workloads competing for it. No other Linux desktop shell does this. Every other thing Aphotic does (themes, bars, a launcher, a plugin platform, agent tracking) has an analogue somewhere else. Resource arbitration between desktop workloads does not. See Why Aphotic for the problem this exists to solve.

What it does

When two workloads want the same finite resource, Aphotic detects the contention and asks which one wins. It never decides for you, and it never kills anything.

Workload -> Resource Claim -> Contention -> Negotiation -> Apply -> Monitor -> Restore

The canonical case, live-verified: a local model holding 8226 MB of VRAM, a game registering 13386 MB through GameMode, 22376 MB against a 22108 MB safety budget. A real negotiation gets raised. You answer it. Choose Suspend and Ollama unloads through its own API in about 10 ms: the model steps aside, the game keeps every megabyte it asked for, nothing crashes.

The three boundaries

The implementation enforces these; they aren’t just stated intent.

  1. Nothing gets terminated. The only stop path is a suspendRequested signal to the owning profile’s own graceful-stop hook. A claim stays registered until its owner releases it, so the claim table keeps telling the truth even when a stop is slow or declined.
  2. The engine never touches the kernel or sysctl, and never probes hardware directly. Capacity is declared by whichever domain knows how to measure it (declareResource()). An undeclared resource gets tracked but never arbitrated. Core declares nothing at rest: CPU and system-memory capacity are declared only while something claims against them (reference counted in SystemCapacity), so a base install with nothing running can never raise a negotiation on its own.
  3. The engine never resolves a conflict on its own. Contention produces a negotiation; you answer it. Three choices cover every case regardless of which two domains collided: [Suspend <workload>], [Keep Running], [Ignore]. Negotiations queue instead of stacking, so two conflicts can’t produce two modal prompts at once.

Two filters keep the prompt from asking questions with only one answer. Only a workload that belongs to a registered profile asks for arbitration: the catch-all per-process claims (the compositor, the shell, a terminal) are accounting, not contenders. And a conflict whose current holder has no graceful-stop hook opens no prompt, since “keep running” would be the only possible answer; Flow still shows it as over budget.

A fourth property falls out of the design instead of needing a rule someone has to remember: it stays dormant until claimed. No timer, no background process, no file watch. Nothing runs and nothing costs anything until a domain actually registers a claim.

Where it stands today

Piece State
Core substrate Shipped
Ollama claimant Real, live-verified on NVIDIA
llama-swap claimant Real, live-verified on NVIDIA via llama-server PID adoption
LM Studio claimant Real, through the same shared local-inference claimant as Ollama and llama-swap
System-memory claims A model a backend reports resident in RAM (not on the GPU) claims system memory
Gaming claimant Real, live-verified via GameMode PID adoption
AI-to-Gaming negotiation Proven with both sides real
Dev claimant CPU claims for builds a launcher wrapper reports, sized by their declared worker count, at background priority. Nothing scans command lines
Security claimant Profile and workload passport only; the claim seam exists but is unwired until an engagement’s real cost is measured
NVIDIA capacity detection Hardware-verified
AMD capacity detection Written to spec, not yet run on real AMD hardware
Intel capacity detection Declares nothing on purpose. Intel’s shared framebuffer has no separate VRAM budget to arbitrate
Resource map UI Shipped as Flow, a Command Center tab (2.0.5). See below

llama-swap. Set a llama-swap host in Settings, AI and each model it runs becomes a claim. llama-swap reports model names but not memory, so Aphotic matches each model to the llama-server process serving it and claims that process’s measured VRAM, once, under the llama-swap owner. Choosing Suspend unloads the model through llama-swap’s own API. A llama-swap on another machine holds no VRAM here, so it claims nothing.

LM Studio and Ollama. Both feed the same claimant. VRAM comes from the model’s own process where there’s a PID to adopt, and from the backend’s own report otherwise; memory a backend reports resident outside the GPU becomes a system-memory claim.

Flow

Command Center (Super+D) → Flow is the live map of the engine’s state:

  • Reservoirs — each declared resource (GPU VRAM, CPU, memory) and how much is claimed. A contended one is marked.
  • Workloads — each claimant with its phase, grouped by plane (AI, gaming, security, dev).
  • Claim lens — select a node to see every claim behind it: amount, priority, origin.
  • Reported work and What changed — the workload passports and action receipts behind a node (what started, what was asked to stop, and whether it did), with an Export receipts button.
  • Negotiation bar — a pending negotiation shows at the bottom with a projection of the outcome, and can be answered there (“Keep both” or “Request graceful stop”) as well as from the prompt.
  • Shell activity — an opt-in layer, off by default, that shows what Aphotic itself is using. Measured, never claimed, so it can’t cause a negotiation.

Flow listens only while it is visible and adds no process scanner of its own.

Loading a local model also switches the desktop into inference mode (blur, shadows and animations off, pausable plugins paused) until 20 seconds after it unloads. See Supported Features.

Honest limitation: the engine stays dormant on any install without a local model loaded, a game registered with GameMode, or a reported dev build. Most installs have never seen it negotiate anything. That’s a roadmap gap, not a documentation one. See Project Status.

See also

  • Why Aphotic — the VRAM-crash problem that made this the flagship feature
  • Architecture — where the Resource Engine sits in the shell
  • Plugin System — the profile capability, for a plugin that wants to register its own claimant (Gaming Profile is the worked example)