Ambient system companions over one privacy-preserving signal daemon (aggregate-only, no keystroke content): a git-driven terminal garden and IOKit hardware collectors. ambient daemon macos privacy terminal

Commit 888f0e549d

888f0e549d4effb37213f6f532120b0d21042454

parent: 3c8c952802

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-04 16:54 UTC

Add a CHANGELOG

Seven tags and no release notes, with the wire contract having moved twice and
nothing recording when or why.

Written from the repository's history: 24 commits across 7 tags, described by
net effect per release rather than commit by commit. Every SCHEMA_VERSION move
is called out, that being the compatibility contract between the daemon, the
Swift collector and every renderer.

v0.1 and v0.2 are named in the README's phase plan but were never tagged; the
0.3.0 entry says so rather than inventing releases for them.

Closes #15
CHANGELOG.org added +152
@@ -0,0 +1,152 @@
1#+TITLE: Changelog
2#+OPTIONS: toc:nil
3
4Notable changes per release. Dates are release dates; the repository's own
5history has the detail.
6
7=SCHEMA_VERSION= is the wire contract between the daemon, the Swift collector
8and every renderer, so it is called out wherever it moves. From 1.0 onward
9=SignalName= discriminants are append-only: names may be added, never
10renumbered or removed.
11
12* Unreleased
13
14** Fixed
15- The privacy ship-gate's forbidden-symbol scan missed =${BUFFER}=. The braced
16 form is ordinary zsh and does not contain the substring =$BUFFER=, so the
17 check enforcing the project's central claim was bypassable by two
18 characters. =$RBUFFER= was absent entirely.
19- That scan also asserted nothing about having scanned. If the directory walk
20 returned empty the test passed having read no files, reporting success while
21 checking nothing.
22- The banned list widened by prefix where safe: =CGEvent=, =IOHID=, plus
23 =addLocalMonitorForEvents=, =AXObserver= and =AXUIElement=. Bare =NSEvent=
24 stays permitted — the keylogger-shaped API is the monitor, not the class, and
25 a menu-bar face will need it to draw a UI.
26
27* 1.1.0 — 2026-09-04
28
29** Added
30- =terminal-pet --oneline=: one line, then exit, for a shell prompt segment.
31 About 2.7 ms per call including process start. With no daemon it prints
32 nothing and exits non-zero, so a prompt segment hides itself rather than
33 printing a diagnostic into the prompt.
34- =signal_client::Frames::snapshot=, which reads the daemon's last-value cache
35 and returns without waiting out a timeout.
36
37** Fixed
38- The pet's mood ignored staleness, so a cached keystroke rate left it looking
39 busy indefinitely. The terminal collector stops publishing once a session
40 ages out of its active window, so the last rate sat in the cache with nothing
41 to replace it. Mood now considers only current readings.
42
43* 1.0.0 — 2026-09-04
44
45The release that makes one claim: the daemon runs unattended, recovers from its
46own failures, and says so when it cannot. Not feature completeness — two of the
47five faces in the README exist, and the rest are explicitly post-1.0.
48
49=SCHEMA_VERSION= 4 → 5.
50
51** Added
52- =SignalName::CollectorUp= (discriminant 11), the daemon's own health,
53 published once per =Source= on state changes. A dead collector now reaches a
54 face instead of a log file.
55- =signald/src/supervisor.rs=: collector liveness in one place. The hardware
56 child is respawned with backoff from 1 s doubling to a 60 s cap, reset after
57 a run surviving 30 s, with no retry limit.
58- =terminal-pet=, the second face: the shell, the machine, and collector
59 health. Any collector down renders the pet sick, which outranks every other
60 mood.
61- =crates/signal-client=, one definition of the socket path and of frame
62 iteration, shared by the daemon and both renderers.
63
64** Fixed
65- A panic in the git or terminal collector killed the producer thread while the
66 socket kept serving a frozen cache, so faces went on rendering numbers that
67 had stopped being true. A panic now costs one tick.
68- The hardware collector was spawned once and never again. If the child died,
69 the daemon stayed up, so launchd's =KeepAlive= never fired and hardware
70 signals stopped for good.
71- =run_git= used =.output()= with no timeout, so a held index lock or a
72 vanished network mount hung the producer thread forever while health still
73 read up.
74- =keys_per_min= had no floor on its sample window: two prompts a millisecond
75 apart extrapolated a handful of keys into a five-figure rate.
76- The zsh hook capped the spool at 1 MiB. Nothing consumes it while the daemon
77 is away, and the daemon read the whole file on recovery.
78
79** Changed
80- The hub's last-value cache keys by name, source and tag. It keyed by name and
81 tag, so two signals differing only by source overwrote each other.
82- =Signal.ts= no longer claims to be monotonic-corrected. It cannot be: it is
83 persisted, retention prunes on it, and =CommitsToday= means since local
84 midnight.
85
86* 0.6.1 — 2026-09-04
87
88** Fixed
89- =signald= had no =--help=, and any unrecognised argument became a repository
90 path — so =signald --help= started the daemon watching a directory named
91 =--help=. Both binaries now have =--help= and =--version=, and an unknown
92 option exits 2.
93
94* 0.6.0 — 2026-09-04
95
96** Added
97- An install path. =packaging/net.krz.signald.plist= runs the daemon at login;
98 a Homebrew formula in =krz/homebrew-tap= installs the binaries, the plist and
99 the zsh hook, with =brew services= support.
100- =~/.config/signald/repos=, read when no repository is given on the command
101 line. launchd starts an agent in =/=, so without it a service install
102 collected no git signals at all.
103- A README "Paths" table: the socket, history database and spool defaults in
104 one place.
105
106* 0.5.0 — 2026-09-04
107
108The contract freeze. =SCHEMA_VERSION= 3 → 4.
109
110** Changed
111- =SignalName= cut from 29 variants to the 11 with a producer, and its
112 discriminants renumbered from zero. The last release in which renumbering was
113 possible.
114- =Tag::bundle_id= and =Tag::ssh_host= removed: both were =todo!()= panics
115 whose only consumers were among the removed variants. =Tag::repo_path= is the
116 sole constructor, and =signald= confines a tag to the roots it was told to
117 watch.
118
119** Fixed
120- A frame the build could not decode ended the stream, so a renderer built
121 before a metric was appended died on the first one it met. Such frames are
122 now skipped; an error is reserved for a stream that cannot be framed at all.
123- Around 34 citations of a specification that was never committed, replaced by
124 the rules they referred to.
125
126* 0.4.0 — 2026-09-04
127
128One bus: every collector reaching every subscriber by the same path.
129
130** Added
131- Hardware ingest. =signald= spawns =macos-collector= and reads its frames, so
132 the five hardware signals reach the hub, the history store and every
133 subscriber like any other collector's.
134- A 0BSD =LICENSE=.
135
136** Changed
137- The terminal spool is consumed each tick rather than re-read in full forever,
138 and its records carry the shell's pid, so =keys_per_min= is each active
139 shell's rate summed rather than a mix of interleaved sessions.
140- History rows older than =--retention-days= (default 7) are pruned.
141- CI was added and then removed within this release. The forge's runner is
142 scoped to one repository, so builds queued here were never claimed;
143 =.githooks/pre-push= runs the whole suite instead and is the only gate.
144
145* 0.3.0 — 2026-08-10
146
147First tagged release: the signal daemon, the git, terminal and IOKit
148collectors, and the privacy-gated =f64=-only schema at =SCHEMA_VERSION= 3.
149
150The v0.1 and v0.2 milestones named in the README — the git collector and the
151garden, then the SQLite history store, live streaming and the terminal
152collector — were never tagged and are folded into this commit.
README.md +6
@@ -305,6 +305,12 @@ neither, the working directory is watched.
305305Unix socket paths are limited to about 104 bytes. A deep scratch directory
306306will hit `SUN_LEN`; use `mktemp -d` when testing by hand.
307307
308## Changelog
309
310Notable changes per release are in [`CHANGELOG.org`](CHANGELOG.org), including
311every `SCHEMA_VERSION` move — the wire contract between the daemon, the Swift
312collector and every renderer.
313
308314## Build & test
309315
310316```sh