Skip to content

JSON Schemas

Prakhar Yadav edited this page Sep 16, 2026 · 1 revision

JSON Schemas

All schemas are versioned; breaking changes bump the v1. Additive booleans (monitor_only, auto_restore_pending, polls) did not change the ids.

afanctl.status.v1 (status --json)

{
  "schema": "afanctl.status.v1",
  "daemon": { "running": true, "mode": "curve", "monitor_only": false, "auto_restore_pending": false, "watchdog_armed": true, "uptime_s": 981 },
  "sensors": [ { "label": "Core 0", "temp_c": 53.0 } ],
  "effective": { "temp_c": 53.0, "method": "max" },
  "fan": { "rpm": 1203, "min_rpm": 1200, "max_rpm": 7200, "target_rpm": 1200, "manual": false },
  "config": { "high_c": 66, "max_c": 86, "min_rpm": 1200, "max_rpm": 6200, "interval_s": 1,
              "source": "/etc/afanctl/afanctl.toml" },
  "recent_errors": [ { "ts": "2026-09-14T15:02:11+05:30", "msg": "" } ]
}
Field Type Source
daemon.running bool state.json exists
daemon.mode observe|curve|hold state.json, default observe
daemon.monitor_only bool state.json (degraded latch)
daemon.auto_restore_pending bool state.json (unverified release)
daemon.watchdog_armed bool notify socket reachable
daemon.uptime_s int polls × interval_s (legacy fallback watchdog_pings × interval_s)
sensors[].label / temp_c string / float|null live sysfs reads (null = failed read)
effective.temp_c / method float|null / max max over valid sensors
fan.rpm/min_rpm/max_rpm/manual int/int/int/bool live sysfs reads
fan.target_rpm int|null state.json (null when daemon down)
config.* ints loaded config
config.source string config path, or defaults
recent_errors[] {ts, msg} state.json (last 5), else []

afanctl.cmd.v1 (/run/afanctl/cmd.json)

{ "schema": "afanctl.cmd.v1", "mode": "hold", "rpm": 3000 }
Field Type Notes
schema string always afanctl.cmd.v1
mode observe|curve|hold unknown → logged + ignored
rpm u32 hold only; out-of-range → logged + ignored

Atomic tmp+rename write. Freshness-gated on read (byte-identical re-issues ignored).

afanctl.state.v1 (/run/afanctl/state.json)

{ "schema": "afanctl.state.v1", "ts": "", "mode": "curve", "t_eff_c": 71.2,
  "target_rpm": 3400, "last_written_rpm": 3350, "actual_rpm": 3390,
  "verified": true, "monitor_only": false, "auto_restore_pending": false, "polls": 981,
  "watchdog_pings": 1962, "recent_errors": [ { "ts": "", "msg": "" } ] }
Field Type Notes
schema string always afanctl.state.v1
ts string UTC YYYY-MM-DDTHH:MM:SSZ
mode string observe|curve|hold (commanded mode, kept during degradation)
t_eff_c float|null effective temp °C
target_rpm int|null decision target, clamped to hw band
last_written_rpm int|null applied.or(last_written)
actual_rpm int|null last observed tach
verified bool !monitor_only && l1_ok
monitor_only bool degraded latch (additive)
auto_restore_pending bool unverified release (additive)
polls int completed polls, 1/poll — uptime source (additive)
watchdog_pings int L3 audit, 2/poll — never uptime
recent_errors array ring, last 5 {ts, msg}

Atomic tmp+rename write, every poll. Serialize/write failures are logged and never abort control.

afanctl.doctor.v1 (doctor --json)

{
  "schema": "afanctl.doctor.v1",
  "checks": [ { "name": "", "status": "PASS", "detail": "" } ],
  "compare": {
    "samples": 600, "lost": 0, "mean_delta_rpm": 191.0, "max_abs_delta_rpm": 2260,
    "quieter": 198, "louder": 392, "equal": 10,
    "rows": [ { "t_eff_c": 63.0, "smc_rpm": 1200, "our_rpm": 1200, "delta_rpm": 0 } ],
    "verdict": ""
  }
}

compare is present only when --compare N ran. status is one of PASS/FAIL/WARN per check (same fields as the human output).

Clone this wiki locally