For agents, on top of README.md, which they read first.
Notes for agents
- The user of this product is a young child. Every conversation is logged and visible to the parents; that is a requirement, not an option to trade away. Nothing reaches the child without passing the guard. A failure of the model, the guardrail or the network ends in a safe spoken fallback, never in silence or raw error text.
- Never log content. Nothing the child or Whiskers said, no memory facts, no summaries, and not the child's name. Log lengths, counts, ids, durations and whether a profile is set.
- The child is a profile, never a literal. Name and age live in
HouseholdConfig::child(whiskers-core/src/profile.rs) and reach prompts and the guard only throughAudience. Do not write a name, an age or a pronoun for the child into code, tests, fixtures, docs or comments; test fixtures useAda, age 6. With no profile the guard assumes the youngest supported age (Age::YOUNGEST): a missing profile must never be the loose case. - Nothing identifying goes in tracked files. No family details, hostnames, IPs, device serials,
user names, personal paths or secret names: they are build properties and environment variables.
tools/check-private.shenforces a deny-list kept in the gitignored.private-terms; run it before committing. It also checks commit messages (--message) and every unpushed commit (--push): the repository is served in full through the code host, so a term in an old commit or a message is as public as one in a file; the hk hooks run both. Never run a push without it, and do not pipe its output (a pipe hides the exit status). Operator-private notes belong outside this repository. - No non-native user interface. Rust core, Kotlin shell with Jetpack Compose. Logic belongs in the core; the shell draws and listens.
- Jev decides whether a message is allowed; a model writes the parents' summary. Shared Jev
client code lives in
third-party/jevcrates(a submodule); do not write a second client here. - Measure on the device before designing around it. Speech recognition, the child profile and the Fire OS version differ per device. Do not assume a Google service exists on Fire OS.
- Pushing is the owner's call, per push.
mise.tomlis the one place for tool versions, environment variables and tasks. Nix is an optional wrapper (flake.nixprovides mise and native libraries and packages the service); it holds no version. Anything that must repeat a version (a Cargo pin, the Gradle SDK levels,hk.pkl) is checked bytools/check-versions.sh. A README tells people to runmise run <task>, never cargo, gradle, adb or nix directly: add the task.- Nobody is required to have nix. Do not write a script, task or doc that needs it, and do not make
nixthe first command in a README. - No banner comments. A comment is read as markdown on the code host, so a ruled or dashed heading is noise there. Write
// ## Title(or# ## Title) for a heading, or nothing.tools/check-banners.shfails on the lines a commit adds (an hk pre-commit step);mise run check-bannerslists every one in the tree.