Skip to content

Add a unified machine pulse and phone-safe resource stream #360

Description

@8Dionysus

Context

abyss-machine already owns the relevant host facts and decision surfaces:

  • doctor and machine reports
  • resource status, plans, admission, and runtime leases
  • memory status, PSI, swap, cgroups, and process attribution
  • storage status
  • process snapshots and thermal attribution
  • cooling, mode, power, and heartbeat state
  • stack observability bridges

What is missing is one compact, continuously refreshable read model that answers the operator's immediate question:

How occupied is the machine now, what is actually free, and what class of new work can safely start?

This should become the canonical source for a phone panel, desktop widget, agent context packet, and future mobile approval UI. Mobile biometric authorization is tracked separately in #359.

Principle

Compose existing bounded read models and live adapters. Do not create a second independent monitoring stack or duplicate collectors merely to draw a dashboard.

The pulse should distinguish:

  • raw utilization
  • pressure and reserve
  • current owners/workloads
  • admission capacity for new work
  • unavailable/unsupported measurements

A CPU at 30% is not automatically "free" if thermal, memory, storage, or foreground-owner constraints block heavy work.

Proposed surfaces

Snapshot

abyss-machine pulse --json
abyss-machine pulse --compact
abyss-machine pulse validate --json

Persist private generated state under the installed host state root, for example:

/var/lib/abyss-machine/pulse/latest.json
/var/lib/abyss-machine/pulse/history/YYYY/MM/YYYY-MM-DD.jsonl

Stream

Provide a bounded read-only local stream after the snapshot contract is stable:

abyss-machine pulse serve --listen 127.0.0.1 --json

Transport may be SSE, a Unix socket, or another deliberately small mechanism. It must bind to loopback/Unix socket by default. Phone access should use an explicit SSH/Tailscale tunnel rather than a public unauthenticated port.

Minimum pulse document

Identity and freshness

  • schema/version
  • host ID
  • observation timestamp
  • collection duration
  • freshness/partial/error state for each section

CPU

  • total utilization and load averages
  • optional per-core utilization
  • effective/average frequency when available
  • package temperature and throttling evidence
  • PSI or scheduler-pressure evidence where useful

GPU

  • backend/device identity
  • engine utilization when supported
  • VRAM/local-memory used, available, and total when supported
  • temperature, power, and throttling when supported
  • explicit unsupported/unavailable states instead of invented zeroes

Implement adapters by capability, for example Intel, AMD, and NVIDIA probes, without making any one vendor mandatory.

Memory and swap

  • total, used, available, reclaimable/cache
  • PSI some/full
  • swap total/used/free
  • zram state when present
  • swap-in/swap-out activity over the sample window
  • reserve debt / headroom using existing memory semantics

Storage and I/O

  • critical filesystem free space
  • I/O pressure and busy state where available
  • current storage policy verdict

Workloads and ownership

  • active resource leases/reservations
  • active heavy/sustained workloads
  • top bounded CPU, memory, and GPU consumers
  • owner/activity classification where known
  • no raw environment, secrets, or unbounded command lines in the phone-safe projection

Thermal, cooling, and power

  • thermal class
  • relevant temperatures
  • cooling/fan state where trustworthy
  • external power/battery state
  • active power and machine mode

Admission summary

Expose a human-readable and machine-readable verdict for each class:

  • probe
  • light
  • medium
  • heavy
  • sustained

Each verdict should say allow, wait, warn, or deny, with bounded reasons derived from existing resource, memory, game, thermal, storage, and owner-aware admission policy.

Example compact shape:

{
  "state": "busy",
  "headline": "Heavy work should wait: memory reserve is low and foreground activity is present",
  "cpu": {"used_percent": 42.1, "thermal": "normal"},
  "gpu": {"used_percent": 8.0, "memory_used_mib": 612},
  "memory": {"available_mib": 3280, "pressure": "watch"},
  "swap": {"used_mib": 1040, "activity": "quiet"},
  "admission": {
    "light": "allow",
    "medium": "warn",
    "heavy": "wait",
    "sustained": "deny"
  }
}

Sampling and retention

  • Reuse shared samples within one pulse collection to avoid repeatedly reading /proc, /sys, sensors, and subprocess tools.
  • Support an interactive cadence around 1 second without requiring history writes every second.
  • Downsample persisted history, for example 10–60 second summaries plus meaningful transitions.
  • Record state changes and threshold crossings, not an endless firehose by default.
  • Bound subprocess timeouts, output bytes, process lists, and history size.

Phone-safe projection

The first mobile consumer may be a simple web/PWA or Android surface. The repository should own only the stable pulse contract and local transport. The phone UI should be able to show:

  • large current CPU/GPU/RAM/swap gauges
  • temperature and power state
  • active heavy workloads
  • "free / occupied / pressured" headline
  • whether a new agent, indexer, benchmark, or model load can start
  • alerts and stale-data warnings

Later, the same surface can display privileged approval requests from #359 without mixing the read-only pulse trust boundary with the write/approval boundary.

Acceptance criteria

  • A pure pulse contract composes existing subsystem documents without live I/O.
  • Live collection reuses bounded adapters/samples and reports unsupported fields explicitly.
  • CPU, memory, swap, storage, thermal/power, workload, and admission sections are present.
  • GPU capability probing supports optional vendor-specific adapters and graceful absence.
  • abyss-machine pulse --json produces a compact current snapshot and writes latest.json only when requested/policy permits.
  • A phone-safe projection omits secrets, raw environment, private paths, and unbounded argv.
  • Admission summaries remain policy-derived and do not infer importance from pressure alone.
  • Stream transport is loopback/Unix-only by default, bounded, read-only, and validates freshness.
  • Sampling/history policy prevents high-frequency disk churn.
  • Public smoke tests use synthetic fixtures; live host tests are opt-in and read-only.
  • Documentation explains the difference between utilization, pressure, reserve, and admission capacity.

Non-goals

  • replacing Prometheus/Grafana for long-term fleet analytics
  • exposing host telemetry directly to the public internet
  • duplicating existing resource/memory/storage/cooling policy engines
  • treating swap occupancy alone as current memory pressure
  • allowing the dashboard or phone client to mutate host state

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions