1# Whiskers 2 3A talking cat companion for a young child. Site: [whiskers.lmjtfy.fun](https://whiskers.lmjtfy.fun) · code: [code.lmjtfy.fun/whiskers.git](https://code.lmjtfy.fun/whiskers.git). The child taps the cat, speaks, and hears a spoken 4answer. The parents see every conversation, get a summary of the day, set time limits, and can 5make Whiskers forget things. 6 7**Status:** a working demo. The Rust core, the service (`whiskersd`) and the Android app run and 8their tests pass. Speech recognition, the camera and the natural voice depend on the device and 9are not verified on every Android flavour; the target is an Amazon Fire HD Kids tablet (Fire OS 8, 10Android 11, no Google services). 11 12## How it is meant to be used 13 14- A Kotlin app is installed on the child's tablet. The mascot is a robot cat; the child taps it, 15 it shows it is listening, transcribes the child's voice, and sends the text on. 16- The first time the app is opened the parents open **About your child** (behind the grown-up 17 lock) and enter the child's name and age. Everything Whiskers says is written for that child: 18 the greeting, the persona, how carefully each message is judged, the parents' summary. 19 Until it is filled in Whiskers speaks neutrally and judges as carefully as it would for the 20 youngest supported age (3). 21- Every conversation is logged and visible to the parents; that is a requirement, not an option. 22 Nothing reaches the child without passing the guard, and a failure of the model, the guard or the 23 network ends in a safe spoken fallback, never in silence or raw error text. 24- The grown-ups choose daily limits, quiet hours, a thinking allowance and a PIN. These, and the 25 child's profile, are one document the devices keep level with the service. 26- It remembers things the child mentions (a toy's name, a friend), shows them to the parents, and 27 lets them be forgotten. The child can show it pictures; they are described by a separate model 28 call and the description is judged before the cat sees anything. 29 30## What it looks like 31 32These are the Android screenshot tests' goldens, so they are always the current look (all of them: 33[`android/README.md`](android/README.md)). 34 35| the grey cat listening | the ginger cat speaking, with captions | the parents' side | 36|---|---|---| 37|  |  |  | 38 39## Build it 40 41<img src="assets/mise-logo.svg" alt="mise" height="32" align="left"> Use [mise](https://mise.jdx.dev): it installs the whole toolchain from [`mise.toml`](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. 42 43 mise trust 44 mise install 45 mise run check 46 mise run android:debug 47 mise run dev 48 mise tasks 49 50`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](fnox.toml), see [tools/README.md](tools/README.md). 51 52### Optional: nix 53 54Nix 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](tools/README.md). 55 56## Architecture 57 58One Rust core of portable crates with no user interface, and a thin native shell per platform. 59Conversation state, memory, the log, the guard policy and the gateway client are in the core; a 60Kotlin and Jetpack Compose shell draws the cat and listens. Never a web view or a self-drawing 61framework. 62 63| Part | What | 64|---|---| 65| [`crates/`](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). | 66| [`android/`](android/) | The app. | 67| [`assets/`](assets/) | The ginger cat's SVGs and the script that writes them, and mise's logo. | 68| [`tools/`](tools/) | Build, install and operate scripts. | 69| `mise.toml`, `hk.pkl`, `fnox.toml` | The toolchain, environment, tasks and daemons; the git hooks; the secrets whiskersd needs (declared, no values). | 70| `flake.nix` | Optional nix wrapper: a shell with mise, and the service package. | 71 72The model is reached through a gateway you run (an Anthropic Messages API), proxied by `whiskersd` 73so the tablet holds no keys. The guard is a Jev (TypeSafe) judge; the natural voice is ElevenLabs 74(optional; the device falls back to an on-device voice). `whiskersd` needs your own keys and 75addresses: see [crates/whiskersd/README.md](crates/whiskersd/README.md) and 76[android/README.md](android/README.md). 77 78## The website 79 80[`web/`](web/) is the public page, a Rust and Datastar Cloudflare Worker for 81[whiskers.lmjtfy.fun](https://whiskers.lmjtfy.fun), in the style of lmjtfy. It is live; see its README. 82 83## Other hosts for the backend 84 85[`backend/`](backend/) holds the adapters of the ports that run on Cloudflare and on celld (a Worker with one Durable 86Object per household), each its own workspace, and the tool that checks every host against the same questions. Not deployed. 87 88## Privacy of the repository 89 90Nothing about a particular family or machine belongs in this repository: names, addresses, device 91serials and tailnet or LAN details are configuration, not code. `tools/check-private.sh` fails if a 92term from your own gitignored `.private-terms` file appears in any tracked file; see 93[tools/README.md](tools/README.md).