shell-hooks
shell-hooks
Shell side of the terminal collector (spec §1.4). Live as of v0.2. These
snippets belong in the dotfiles repo and are sourced by the user's .zshrc;
they are kept here so the privacy contract lives next to the code it constrains
(and so the differential secret-typing test can drive the real file).
The one rule
Aggregate-only. The hooks emit counts, durations, and exit codes. They never read, store, or transmit the content of a command or a keystroke.
- No input tap, no
CGEventTap, no PTY sniffing. - Never reference the
zleline buffer or capture argv. - What leaves the shell is a number, flushed on
precmd.
v0.2 ships the zle keypress counter: a widget wraps self-insert, does
(( _SIGNALD_KEYS++ )), then calls the built-in insert. It receives the key in
the editor and discards it — the character is never assigned to a variable that
outlives the widget and never leaves the shell. On each precmd the hook
appends one count record — <epoch_ms> <keys> <session_seconds>, numbers only
— to $SIGNALD_SPOOL, which signald reads.
This contract is enforced by the forbidden-symbol scan and the differential
secret-typing test in crates/signal-schema/tests/privacy_invariant.rs (plus
the full-pipeline gate in crates/signald/tests/), which drive this file with
a planted secret and fail the build if it — in any encoding — reaches the spool,
the wire, or SQLite.
Files
signald-hooks.zsh— thezlekeystroke counter +precmdcount flush (aggregate-only).