For agents, on top of README.md, which they read first.
Notes for agents
- No hosting words in here. Never name Cloudflare, celld, wrangler, Durable Objects, R2/buckets or
fetch/Request/Responsetypes in this crate, in code or docs, except to say that an adapter is not this crate. The port is Whiskers' own; the adapter adapts to it, not the other way round. If a port seems to need a host's concept, the port is mis-shaped: change the port's language, not its dependencies. - Must build for
wasm32-unknown-unknown. Nostd::fs,std::net,std::thread,SystemTimeorInstant. Check withcargo check --target wasm32-unknown-unknown -p whiskers-portsinsidenix develop ~/whiskers. Dependencies stay atserde,serde_json,logandwhiskers-core. serde_jsonhaspreserve_orderon purpose. Stored journal lines keep a device's key order, and every JSON reply of the service is laid out the same on every backend. Do not remove the feature.- A capability is a trait here, its laws in
whiskers-conformanceand its routes inwhiskers-service. Adding one touches all three (the README's "Capabilities" section lists the steps). Never write a stand-in port to satisfy a bound, never add a runtime "not configured" branch to a route for a capability the adapter may lack, and never put a new capability only inBackend's supertraits without aHas…trait of its own: an adapter must be able to hold it alone. - A contract is a law in
whiskers-conformance. Changing a contract means changing its law in the same commit; adding a port means adding its laws and running them against the in-memory adapter and the native one. A law no adapter can fail proves nothing: keep the "caught" tests in that crate. - Make the wrong thing unrepresentable. Anything that arrives from outside gets a validated newtype with
a private field (
DeviceName,SafePictureId,SpeechLine...). Errors are enums that say why; a string goes in aDiagnosticand is never branched on. Add a variant rather than parse a message. - Rules live in
whiskers-coreor here, not in adapters. The merge rules, the window arithmetic (ThinkingLedger), the day arithmetic (VoiceDay) and the page rule (Page::of) are shared on purpose: an adapter decides where state is kept and how access is serialised, and adds nothing to the arithmetic. - Logging follows
crates/CLAUDE.md: levelled lines, never content. whiskers-corealso has aportsmodule (Model,Guard,Log...): those are what a device's conversation pipeline runs through. These are the backend's. They are different layers.