Expand description
NATS KV bucket name + key helpers (spec §2.3.2).
NATS KV bucket names must be domain-safe ASCII (a-z, A-Z, 0-9, _, -),
so the spec’s dotted names (script.current, script.status) are
flattened to underscore form here.
Constants§
- ALL_
KV_ BUCKETS - Every KV bucket
ensure_jetstream_resourcescreates. The*_yamlsource-of-truth buckets and the operator-managed singletons (fleet_config,group_contacts) are included — they’re part of the bootstrap contract, so a missing one is a genuine degradation. Lazily- created buckets that bootstrap does NOT guarantee (e.g.views,scheduler_dispatch) are deliberately excluded so a fresh fleet that never used them doesn’t read as degraded. - ALL_
OBJECT_ STORES - Every Object Store
ensure_jetstream_resourcescreates. The status probe used to list onlyagent_releases, which is why the dashboard’s “Object stores” column looked suspiciously empty. - ALL_
STREAMS - Canonical list of every JetStream resource
crate::bootstrap::ensure_jetstream_resourcescreates. The health rollup (/api/health/fleet) and the status snapshot (/api/jetstream/status) both iterate these so the dashboard reports the complete resource set — previously each kept its own hand- maintained subset that drifted behind bootstrap (e.g. only 1 of the 5 object stores showed up). Keep in lockstep withbootstrap.rs: a new stream / bucket / store added there must be appended here too. Thecanonical_resource_lists_are_sanetest below guards the easy mistakes (dots, dupes, empties); keeping the set aligned with bootstrap stays a manual discipline (bootstrap needs per-resource config, so it can’t be derived from a name list alone). - BUCKET_
AGENTS_ STATE - BUCKET_
AGENT_ CONFIG - BUCKET_
AGENT_ GROUPS - BUCKET_
FLEET_ CONFIG - Fleet-wide singleton settings that aren’t per-agent (so they don’t
belong in
agent_config’s layered scopes) and aren’t per-schedule (so they don’t belong inschedules). First and only key so far isKEY_FREEZE(#418 Phase 5 global change-freeze). One small bucket both the backend scheduler and every agent’s local scheduler watch. - BUCKET_
GROUP_ CONTACTS group_contacts— per-group notification email addresses, keyed by group name, value JSONGroupContacts. Operator-managed via the SPA Groups page. Distinct fromagent_groups(per-PC membership) andagent_config’sgroups.*scopes (agent config pushed to machines): this is operator contact info, read backend-side to fan a compliance alert out to email.- BUCKET_
JOBS - Job catalog (v0.15) — operator-registered Manifests, keyed by
manifest.id. Schedules and ad-hockanade run --job-id ...look jobs up here; the wire never round-trips an inline Manifest body through a Schedule again. Editing a job in-place retroactively changes what future schedule fires deploy. - BUCKET_
JOBS_ YAML - Parallel “operator source-of-truth YAML” stores keyed identically
to
BUCKET_JOBS/BUCKET_SCHEDULES. The agent / scheduler / projector all keep reading the JSON KVs above — these buckets exist only so the SPA’s YAML editor can round-trip operator comments + script indentation + block-scalar style exactly. - BUCKET_
NOTIFICATIONS_ READ notifications_read— per-user read/ack state for end-user notifications (SPEC §2.3.2 / Phase E). Key shape{pc_id}.{user_sid}.{notification_id}, value JSON{"acked_at": ..., "acked_by": "<sid>"}. The agent writes a row when it handles a KLPnotifications.ack, stamping the connecting user’s OS-derived SID — so a shared PC tracks each user’s reads independently. The{pc_id}.{user_sid}.prefix letsnotifications.listfetch one user’s read set with a single prefix walk.history: 1— only the latest ack per key matters.- BUCKET_
SCHEDULER_ DISPATCH - KV bucket holding per-(schedule, pc) last-dispatch marks for the backend scheduler’s in-flight suppression.
- BUCKET_
SCHEDULES - BUCKET_
SCHEDULES_ YAML - BUCKET_
SCRIPT_ CURRENT - BUCKET_
SCRIPT_ STATUS - BUCKET_
SERVER_ SETTINGS - Backend-side, operator-editable server settings that aren’t per-agent
(so they don’t belong in
agent_config’s layered scopes) and aren’t a fleet-wide switch every agent watches (so they don’t belong infleet_config). A single JSON document underKEY_SERVER_SETTINGSholdingcrate::wire::ServerSettings, managed via the SPA Settings page’s “server settings” tab. Deliberately generic: future server-side knobs join the same document rather than spawning a bucket each. First consumer is the cleanup task’s dead-agent prune window (ServerSettings::agent_prune_days).history: 1— only the current state matters; nothing replays its history. - BUCKET_
VIEWS - View catalog (#743) — operator-registered
Viewresources, keyed byview.id. A view is a pure, declarative read/aggregation over stored fleet data (obs_events, …) for the Analytics page — noexecute, no schedule. The backend reads these at query time and merges their widgets with the co-locatedaggregate:hints on jobs. Distinct fromBUCKET_JOBSso a cross-cutting dashboard doesn’t need a noop job carrier. - BUCKET_
VIEWS_ YAML - Operator source-of-truth YAML mirror for
BUCKET_VIEWS(same role asBUCKET_JOBS_YAML): keeps comments/formatting for the SPA editor. - KEY_
AGENT_ CONFIG_ GLOBAL - Sprint 6 layered-config keys inside
BUCKET_AGENT_CONFIG: - KEY_
AGENT_ TARGET_ VERSION - Key inside
BUCKET_AGENT_CONFIGcarrying the broadcast target version. Agents watch this key and self-update when their running version drifts. - KEY_
FREEZE - Singleton key in
BUCKET_FLEET_CONFIGholding the JSON-encodedcrate::manifest::Freeze. Key absent ⇒ not frozen (clearing the freeze is a KV delete), so readers treat a missing key as “fire normally” and only evaluateFreeze::is_activewhen the key exists. - KEY_
SERVER_ SETTINGS - Singleton key in
BUCKET_SERVER_SETTINGSholding the JSON-encodedcrate::wire::ServerSettings. Key absent ⇒ all-default settings (e.g.agent_prune_days = 0, pruning disabled), so a fresh deployment behaves exactly as it did before the bucket existed. - OBJECT_
AGENT_ RELEASES - Object Store bucket holding raw agent binaries (one object per
version, e.g.
0.2.0→ file bytes). - OBJECT_
APP_ PACKAGES - Object Store holding generic application packages — anything the agent / kitting scripts pull down + install on endpoints. First consumer is the kanade-client app, but the bucket is intentionally generic: third-party installers (Webex, Teams, custom MSI bundles), upgrade scripts, configuration archives, etc. all live here.
- OBJECT_
COLLECTIONS - Object Store holding collected file bundles (#219). A job
carrying a
collect:manifest hint prints a JSON list of file paths on stdout; the agent zips them and uploads the archive here, recording the key incrate::wire::ExecResult::collect_object. The SPA Collect page lists / downloads bundles straight from this bucket. Object keys follow<pc_id>/<job_id>/<rfc3339>.zip, or<pc_id>/<job_id>/<label>__<rfc3339>.zipwhen a run emits multiple labeled bundles (e.g. one zip per day), so a listing groups by host then job. Per-bucket retention is 30 days (bundles are debugging/audit artifacts, not curated config likeapp_packages/scripts, so they auto-expire) — seekanade-shared::bootstrap. - OBJECT_
RESULT_ OUTPUT - Object Store holding overflow stdout / stderr blobs for the
ExecResultwire kind (#227). The default NATSmax_payloadis 1 MB; a result whose stdout / stderr exceeds it would reject the publish and pin the agent’s outbox in a reconnect loop. The agent uploads any stdout / stderr larger thanSTDOUT_INLINE_THRESHOLD(256 KB, picked at 1/4 of the default max_payload so the rest of the ExecResult fields fit alongside) into this bucket and replaces the inline field withcrate::wire::ExecResult::stdout_object/stderr_objectpointers. Backend’s results projector derefs the pointers before INSERT so downstream consumers (SQLite, SPA Activity, inventory projector) see the full text the same way they always have. - OBJECT_
SCRIPTS - Object Store holding manifest script bodies referenced by
Execute::script_object(SPEC §2.4.1’s alternative to inlinescript:/ repo-localscript_file:). Per yukimemi/kanade issue #210, this is the “Plan B 4-bucket layout” sibling ofapp_packages— separated because scripts have a different lifecycle than installer binaries: - PREFIX_
AGENT_ CONFIG_ GROUPS - PREFIX_
AGENT_ CONFIG_ PCS - SCRIPT_
STATUS_ ACTIVE - SCRIPT_
STATUS_ REVOKED - STDOUT_
INLINE_ THRESHOLD - Inline threshold for
ExecResult.stdout/.stderr. Larger payloads overflow intoOBJECT_RESULT_OUTPUT. 256 KB = 1/4 of the NATS defaultmax_payload(1 MB) so the rest of the ExecResult JSON (request_id, exec_id, etc.) easily fits below the publish-reject ceiling. - STREAM_
AUDIT - STREAM_
EVENTS - STREAM_
EXEC - STREAM_
INVENTORY - STREAM_
NOTIFICATIONS - JetStream stream retaining end-user notification history (SPEC
§2.3.1 / Phase E). Catches every
notifications.{all|group.X|pc.Y}publish the backend fans out, so a Client App that connects after a notification was sent can still fetch it via KLPnotifications.list. 90-day window — long enough for “what did I miss while on leave” without unbounded growth. UnlikeEXEC, retains all messages per subject (nomax_messages_per_subject): each notification is its own history entry, not a latest-only state. - STREAM_
OBS_ EVENTS - JetStream stream backing the per-PC observability event pipeline
(Issue #246). Distinct from
STREAM_EVENTS(in-flight script lifecycle) —STREAM_OBS_EVENTScarries the timeline data the SPA’s Events page consumes: sign-in/out, power on/off, sleep/ resume, agent milestones, diagnostic bundle pointers. The agent publishes onobs.<pc_id>(seecrate::subject::obs) and this stream catches everything matchingcrate::subject::OBS_FILTERso a backend that boots after the agent doesn’t miss any already-emitted events. - STREAM_
RESULTS
Functions§
- agent_
config_ group_ key - agent_
config_ pc_ key - dispatch_
mark_ pc_ key - Per-pc dispatch-mark key (OncePerPc).
- dispatch_
mark_ target_ key - Whole-target dispatch-mark key (OncePerTarget). One key per
schedule — a per-target fire dispatches the whole target at once, so
there’s nothing per-pc to record. Length-prefixed for symmetry with
dispatch_mark_pc_key. - notifications_
read_ key - KV key in
BUCKET_NOTIFICATIONS_READfor one user’s ack of one notification:{pc_id}.{user_sid}.{notification_id}(SPEC §2.3.2). - notifications_
read_ prefix - Prefix selecting every ack row for one
(pc_id, user_sid)inBUCKET_NOTIFICATIONS_READ—{pc_id}.{user_sid}..notifications.listwalks the bucket keys and keeps those carrying this prefix to compute the caller’s unread set. Pairs withnotifications_read_key. - parse_
agent_ config_ group_ key - Inverse of
agent_config_group_key— returns the bare group name ifkeycarries the groups-scope prefix, elseNone. - parse_
agent_ config_ pc_ key - Inverse of
agent_config_pc_key.