shell-hooks/README.md
36 lines · 1770 bytes
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> <session_id>,
numbers only — to $SIGNALD_SPOOL. The session id is the shell's pid, so
several shells can share one spool and signald still derives each shell's
rate separately. signald consumes the spool on every tick (renames it aside,
reads it, deletes it), so it never grows.
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).