whiskers.git / README.md

Whiskers

A talking cat companion for a young child. Site: whiskers.lmjtfy.fun · code: code.lmjtfy.fun/whiskers.git. The child taps the cat, speaks, and hears a spoken answer. The parents see every conversation, get a summary of the day, set time limits, and can make Whiskers forget things.

Status: a working demo. The Rust core, the service (whiskersd) and the Android app run and their tests pass. Speech recognition, the camera and the natural voice depend on the device and are not verified on every Android flavour; the target is an Amazon Fire HD Kids tablet (Fire OS 8, Android 11, no Google services).

How it is meant to be used

  • A Kotlin app is installed on the child's tablet. The mascot is a robot cat; the child taps it, it shows it is listening, transcribes the child's voice, and sends the text on.
  • The first time the app is opened the parents open About your child (behind the grown-up lock) and enter the child's name and age. Everything Whiskers says is written for that child: the greeting, the persona, how carefully each message is judged, the parents' summary. Until it is filled in Whiskers speaks neutrally and judges as carefully as it would for the youngest supported age (3).
  • Every conversation is logged and visible to the parents; that is a requirement, not an option. Nothing reaches the child without passing the guard, and a failure of the model, the guard or the network ends in a safe spoken fallback, never in silence or raw error text.
  • The grown-ups choose daily limits, quiet hours, a thinking allowance and a PIN. These, and the child's profile, are one document the devices keep level with the service.
  • It remembers things the child mentions (a toy's name, a friend), shows them to the parents, and lets them be forgotten. The child can show it pictures; they are described by a separate model call and the description is judged before the cat sees anything.

What it looks like

These are the Android screenshot tests' goldens, so they are always the current look (all of them: android/README.md).

the grey cat listeningthe ginger cat speaking, with captionsthe parents' side

Build it

mise Use mise: it installs the whole toolchain from mise.toml, the one place every version lives, and runs every task. It needs only git and a C compiler on the machine; no root.

mise trust
mise install
mise run check
mise run android:debug
mise run dev
mise tasks

mise install fetches Rust (with the Android and wasm targets), the Android SDK tools, a JDK, Gradle, Node, wrangler and the other tools once; the first run is large. mise run check runs the fast gates. mise run android:debug fetches the Android platform and NDK it needs and builds the APK. mise run dev starts the service and the website under a supervisor. mise tasks lists everything else (tests, screenshot goldens, release APKs, git hooks, the preflight check). The git hooks are mise run hooks:install; the service's secrets can come from fnox, see tools/README.md.

Optional: nix

Nix is not required. If you already use it, the flake wraps the same toolchain: nix develop gives a shell with mise and the native tools a downloaded toolchain needs, then everything above works the same. packages.whiskersd builds the service. See tools/README.md.

Architecture

One Rust core of portable crates with no user interface, and a thin native shell per platform. Conversation state, memory, the log, the guard policy and the gateway client are in the core; a Kotlin and Jetpack Compose shell draws the cat and listens. Never a web view or a self-drawing framework.

PartWhat
crates/The Rust core, whiskersd (the service that holds the keys) and whiskers-art (the grey cat's drawing, shared by the app and the website).
android/The app.
assets/The ginger cat's SVGs and the script that writes them, and mise's logo.
tools/Build, install and operate scripts.
mise.toml, hk.pkl, fnox.tomlThe toolchain, environment, tasks and daemons; the git hooks; the secrets whiskersd needs (declared, no values).
flake.nixOptional nix wrapper: a shell with mise, and the service package.

The model is reached through a gateway you run (an Anthropic Messages API), proxied by whiskersd so the tablet holds no keys. The guard is a Jev (TypeSafe) judge; the natural voice is ElevenLabs (optional; the device falls back to an on-device voice). whiskersd needs your own keys and addresses: see crates/whiskersd/README.md and android/README.md.

The website

web/ is the public page, a Rust and Datastar Cloudflare Worker for whiskers.lmjtfy.fun, in the style of lmjtfy. It is live; see its README.

Other hosts for the backend

backend/ holds the adapters of the ports that run on Cloudflare and on celld (a Worker with one Durable Object per household), each its own workspace, and the tool that checks every host against the same questions. Not deployed.

Privacy of the repository

Nothing about a particular family or machine belongs in this repository: names, addresses, device serials and tailnet or LAN details are configuration, not code. tools/check-private.sh fails if a term from your own gitignored .private-terms file appears in any tracked file; see tools/README.md.