Task: Show systemd slice/scope info in compass fleet and bearings

Table of Contents

This page documents a task in the Compass quality-of-life improvements: remaining follow-ups story. It captures the goal, current status, acceptance, and any notes or results.

Goal

Surface each environment's systemd scope in compass fleet and compass bearings output, so it is visible which cgroup or scope a session is running under without manually querying systemctl.

Status

Field Value
State DONE
Parent story Compass quality-of-life improvements: remaining follow-ups
Now Nothing.
Waiting on Nothing.
Next Nothing.
Last touched 2026-08-05

Acceptance

  • compass fleet lists the scope name per worktree/session where available; compass bearings shows the current session's own scope/slice; falls back gracefully when a session has no named scope.

Plan

Added in compass.py:

  • _env_systemd_scopes() — queries systemctl --user list-units --type=scope --output=json once and maps each env_name to its running scope types (claude/build/both). Matches claude-<env>-<pid>.scope and build-<env>-<slot>-<pid>.scope patterns via regex. Returns a dict; missing keys mean no scope is running for that env.
  • _current_session_scope() — reads /proc/self/cgroup and extracts the innermost scope unit name and its parent slice, returning (scope, slice) or (None, None) on failure.

cmd_fleet: calls _env_systemd_scopes() once, adds a SCOPE column (max 14 chars) showing claude, build, build,claude, or per worktree. Also included in --format json.

cmd_bearings: shows the current session's scope and slice under the environment section (Scope : claude-merry_newton-*.scope (slice: app-claude-merry_newton.slice)), or a fallback message when running unscoped.

Both fall back gracefully when systemd is unavailable (systemctl missing, /proc/self/cgroup unreadable, or no named scope).

Notes

Test Scenarios

Manual QA scenarios (scaffolded via compass add test_scenario, run through the QA Validation Runner panel) that verify this task. Link new ones here as they're created; the scenario doc itself links back via its "Verifies task" field.

Scenario State Notes
     

PRs

PR Title
#1871 [compass] Show systemd scope/slice info in fleet and bearings

Review

Round 1 (bot review)

Round-1 fixes: regex char-class expanded to include hyphens (env_init.py:505 documents hyphenated env names); JSON placeholder fix (None in row dict, — fallback in display only); hoisted duplicate .env lookup into local; removed redundant import json as _json; moved systemctl call after early-return check; removed unnecessary f-prefix.

# Comment summary File Decision Notes
1 Regex doesn't match hyphenated env names compass.py Fixed — added - to char class [a-zA-Z0-9_.-]+?  
2 SCOPE placeholder leaks into –format json compass.py Fixed — scope stores None/null, — applied in display loop only  
3 Duplicate .env lookup per worktree compass.py Fixed — hoisted env_name into local variable  
4 Redundant import json as _json compass.py Fixed — using module-level json  
5 systemctl call before early-return check compass.py Fixed — moved scope_map after worktree guard  
6 f-prefix on string with no interpolation compass.py Fixed — removed f-prefix  

Result

compass fleet now includes a SCOPE column showing claude, build, build,claude, or per worktree based on running systemd user scopes (one systemctl call, not per-worktree). compass bearings shows the current session's scope and slice under the environment section. Both fall back gracefully when systemd is unavailable or the session runs unscoped.

Two new helpers in compass.py: _env_systemd_scopes() queries systemctl --user list-units --type=scope --output=json and regex-matches claude-<env>-<pid>.scope / build-<env>-<slot>-<pid>.scope patterns. _current_session_scope() reads /proc/self/cgroup to extract (scope, slice).

Acceptance met:

  • fleet lists scope name per worktree where available
  • bearings shows current session's own scope/slice
  • graceful fallback when no named scope exists

Emacs 29.3 (Org mode 9.6.15)