For agents, on top of README.md, which they read first.
Notes for agents
- One crate per capability; a new adapter is a sibling crate, never an edit to
whiskers-core. The core names ports, not vendors. - Build with Cargo for now. The estate default for Rust is Buck2 (see
~/dashboard); that move is open, so do not add aBUCKfile ad hoc. - The backend is ports and adapters.
whiskers-ports(the interface),whiskers-service(the routes' logic) andwhiskers-conformance(the suite) must build forwasm32-unknown-unknown:mise run check-wasm. A new host is a new adapter crate that passes the suite, never an edit to the ports to suit it. - Adding a capability = a trait + its laws + its routes, in that order, across three crates: the
Has…trait inwhiskers-ports(and inBackend's supertraits), the fixture trait andSuitemethod inwhiskers-conformance, the route type inwhiskers-service(plusService::complete, theCompletealias andEVERY_ROUTE). An adapter implements only theHas…traits for ports it really holds and is given only the routes it can serve: no stand-in port, no runtime "not configured" for a capability that is simply absent (the compiler refuses the route). Seewhiskers-ports/README.md. - Toolchain is not on PATH. Use
nix shell nixpkgs#cargo nixpkgs#rustc nixpkgs#gcc -c cargo test.
Logging convention
A correct function leaves a trace; bugs must be debuggable from the logs alone. Every crate uses the log facade (log::debug! etc.; in whiskers-core write ::log::debug! or use ::log::..., because the crate has its own module called log). The one logger is whiskers_core::logging::init(tag), called first in whiskersd, whiskers-cli and (as init_logging()) from the Kotlin shell via whiskers-ffi. It writes 2026-10-04T18:25:51Z LEVEL target: message to stderr, or to logcat under the tag whiskers-core on Android, and it logs panics (location only).
- Level is picked with the
WHISKERS_LOGenvironment variable:error,warn,info(default),debug,trace,off. error: something failed and the turn, request or save was lost.warn: a fallback was taken, a request was refused or a degraded path was used.info: state transitions (turn begins/ends, sync start/finish with counts, merges, budget and time-limit decisions, every request).debug: entry to non-trivial functions with ids, lengths and counts.trace: hot paths (per-tick, per-touch, per-append).- Log every error path with its context before it is returned or swallowed. Pure tiny getters need no line.
- Never log content. This is a young child's private data, and the child's name is part of it. No message or reply text, no facts, no summaries, no API keys, no PIN hash (log "pin set = true"), no URLs that carry secrets or ids that act as one (ElevenLabs voice id). Log lengths, counts, ids of facts and pictures, statuses and durations instead. Error values from other systems are logged as they come; do not build one out of her words.