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

shell-hooks/README.md

v1.1.0
ambient-companions/shell-hooks/README.md rendered · source · history · blame · raw

36 lines · 1764 bytes

shell-hooks

Shell side of the terminal collector. 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 a keystroke count and a session duration. 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 zle line 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 — the zle keystroke counter + precmd count flush (aggregate-only).