Story: Systemd resource management and per-environment isolation

Table of Contents

This page documents a story in Sprint 25. It captures the goal, current status, acceptance criteria, and the tasks that compose it.

Goal

On 2026-07-31 the machine was rebooted: every process was killed under memory pressure. compass services starts processes with a plain subprocess.Popen(start_new_session=True) – no cgroup, so each service is accounted to whatever launched compass (Emacs, a Claude session, a bare shell). Claude sessions do land in app-claude.slice, but flat (no per-environment split) and with no MemoryMax anywhere on the box, so kernel OOM is a global decision that can pick off Emacs or another environment's fleet.

This story makes compass the single wrapper for process lifecycle across the fleet: compass services start, compass claude, compass services status all place work in the right cgroup, with the right limits, and report per-environment – so a runaway environment cannot take down Emacs, the machine, or another environment's fleet.

Full analysis, findings, and the workstream design live in the resource-management design note; this story tracks the implementation.

Status

Field Value
State DONE
Parent sprint Sprint 25
Now Nothing. All unprivileged workstreams (WS-7, WS-1, WS-5 unpriv, WS-4) merged; WS-3 and WS-2 both discovered already implemented (predate this story, Sprint 24 PR #1806); the client-migration and controller-decommission investigation tasks closed (abandoned/done).
Waiting on Someone with root, for WS-5's root half – left as a follow-up, not blocking this story's close.
Next Nothing under this story. WS-5 (root half) and the deliberate-OOM acceptance test, if picked up, belong to a new story; WS-6 stays deferred.
Last touched 2026-08-05

Acceptance

  • compass claude launches into app-claude-<env>.slice, and systemctl --user show on that slice reports a non-infinite MemoryMax.
  • compass services start results in service processes whose /proc/<pid>/cgroup is under the environment's slice, regardless of whether it was invoked from Emacs, a Claude session, or a bare shell.
  • compass services status shows exactly the current environment's fleet, including when nothing is running.
  • Deliberately exhausting memory in one environment kills only that environment; Emacs and other fleets survive. Tested explicitly, with MemoryMax temporarily lowered so the test is quick and safe.
  • compass build --status reports two slots, and a running build appears under app-build-<env>.slice in systemd-cgls.
  • No compass subcommand requires root for normal operation.

Tasks

Task State Start End Description
Per-environment systemd resource limits (Claude slices, services, builds) DONE 2026-08-05 2026-08-05 Implement WS-1 through WS-5 and WS-7 of the resource-management plan: per-environment Claude slices with MemoryHigh/MemoryMax/MemorySwapMax/CPUWeight limits (WS-1); converge compass services onto systemctl –user against the generated ores@ENV.target units, staged behind –legacy (WS-2); compass deploys the generated units instead of printing instructions (WS-3); per-environment status/tree/top views (WS-4); protect Emacs and the interactive session via slice drop-ins (WS-5, unprivileged half); reduce build lock to two slots and run builds inside a memory-capped app-build-ENV.slice (WS-7). See systemd-resource-management-plan.org for full analysis, design decisions, and sequencing. WS-6 (PID 1 ownership) is explicitly deferred and out of scope for this task.
Migrate Qt client to a proper systemd unit ABANDONED 2026-08-04 2026-08-04 Abandoned: systemd –user sessions on this WSLg/XWayland setup cannot reach the X display (confirmed empirically), a real blocker beyond mere architectural inconsistency. See the task's Result.
Investigate decommissioning ores.controller.service and its DB tables DONE 2026-08-04 2026-08-04 Binary/code confirmed already fully gone (Sprint 24, PR #1806). service_definitions/dependencies_tbl confirmed still load-bearing (systemd_generate.py's source of truth). service_instances_tbl/service_events_tbl confirmed genuinely dead (zero readers/writers repo-wide) – filed as a follow-up capture rather than dropped speculatively here. See the task's Result.

Decisions

Out of scope

  • Separate user accounts per environment.
  • True namespaced systemctl (one manager per UID); a per-environment view through compass is accepted as sufficient until the split-services-into-per-service-containers work gives each environment its own PID namespace.
  • Hard CPU quotas (CPUQuota) – CPUWeight is used instead so -j3 build bursts on an idle machine are never penalised.
  • PID 1 ownership (WS-6) – deferred; only pursued if the unit count keeps causing problems after the other workstreams land.

Emacs 29.3 (Org mode 9.6.15)