1# Sigil appliance status v223`sigil appliance status` is the local, read-only contract for appliance4management surfaces such as the planned Decky Loader plugin. Decky remains an5unprivileged controller over the existing `sigil-host.service`; it does not6launch Sigil as a child, host streaming itself, or add a network listener.78```bash9sigil appliance status \10 --config ~/.config/sigil-spark/host.toml \11 --json --schema-version 212```1314The command validates the owner-only configuration and identity, inspects the15authorization document without creating files or taking its writer lock, and16combines that durable state with Sigil's bounded runtime heartbeat. Output is a17single JSON document with `schema_version: 2`.1819Without `--schema-version 2`, the command continues to emit the original v120shape so independently updated scripts and management clients do not break.2122The public document includes only:2324- Sigil version and overall `ready`, `active`, `degraded`, or `unavailable`25 state.26- Redacted host and enrolled-Portal fingerprints.27- Canonically ordered enrollment grants, epoch, and enrollment time.28- Runtime freshness, daemon state, uptime, session state, and a closed set of29 error codes.30- The exact loaded configuration revision, fresh daemon instance ID, and sticky31 `reached_ready` evidence used by the transactional configuration gate.32- The current configuration revision and any pending transaction summary.3334It never includes complete endpoint IDs, invitation material, replay-ledger35entries, session nonces, addresses, PipeWire object names, filesystem paths, or36free-form error text.3738## Runtime authority3940While serving, Sigil holds an exclusive nonblocking lock at41`<state_path>/daemon-v1.lock`. A second daemon using the same state directory42fails before capture, input, or network initialization. The zero-length lock43file remains in place; the open file descriptor is the lifetime guard. When an44XDG runtime directory is available, Sigil also holds45`$XDG_RUNTIME_DIR/sigil-spark/daemon-global-v1.lock`. That per-user lock enforces46the product's one-daemon boundary even if two commands reference different47state directories. Configured production service mode requires a valid private48`XDG_RUNTIME_DIR` and fails before capture or networking if it is unavailable.49Only the explicit direct test-pattern proof may fall back to its per-state lock50without publishing a heartbeat.5152Offline enrollment reset and configuration rollback may fall back to the53durable per-state lock when `XDG_RUNTIME_DIR` is unset. Configuration `set` and54`commit` still require the service's exact runtime authority; management shells55without the environment may supply its private XDG root explicitly with56`--runtime-dir` (Sigil appends `sigil-spark`). Configured service startup itself57continues to require `XDG_RUNTIME_DIR`.5859Sigil atomically publishes60`$XDG_RUNTIME_DIR/sigil-spark/daemon-status-v1.json` at most once per two-second61heartbeat, plus explicit lifecycle transitions. Keeping the heartbeat in the62per-user runtime directory prevents high-frequency process state from entering63durable backups or surviving a reboot. The status file and its child directory64must be regular, owner-only objects. Reads and writes are bounded, refuse65symlinks, and use no-follow opens. Heartbeat I/O runs outside Tokio's async66worker threads.6768The status command treats a missing runtime document as `offline`. A heartbeat69older than ten seconds is `stale`; stale data never claims a live session or70live uptime. Clean shutdown writes `stopping`, shuts down the Iroh router, and71then writes `stopped`. A crash leaves a bounded document that naturally becomes72stale, while the runtime directory itself is discarded at reboot. Every73runtime document is bound to the current host identity before its state is74combined with durable enrollment data.7576Runtime status v2 remains able to read a version-1 heartbeat after an upgrade,77but legacy heartbeats carry no configuration revision and never satisfy the78configuration health gate. Stale or absent heartbeats do not expose an instance79ID, loaded revision, or ready claim.8081The Decky backend merges this document with `systemctl --user` unit state.82Service control, enrollment reset, and identity factory reset remain separate83contracts. Transactional configuration is defined by the84[configuration v1 contract](sigil-appliance-config-v1.md).