Fay

fay is the voice, chat, and display surface for talking to a fleet of Claude agents from phone or desk. Single git repo holding both the Python server, the Android app, and a Brilliant Frame OLED bridge. Private under heiervang-technologies/fay.
fay is the phone that hosts Cinder — every swipe of a decision card lives inside this app.
Repo layout
| Path | Role |
|---|---|
app/ |
Android app — Gradle module, Kotlin under app/src/main/java/com/fay/app/. Flavors: stable / canary / frame.
|
server/ |
Python FastAPI server (tmux_api.py) + canvas HTML (canvas/) + suggestion bake-off.
|
fay-bridge/ |
Python daemon: tails fay-ears.sock transcription events → injects them into the talking-stick holder's tmux pane. The inbound voice path.
|
systemd/ |
Vendored snapshots of the fay user units. |
scripts/ |
Versioning + changelog helpers used by the Version Tag workflow.
|
Surfaces
- fay-tmux-api — FastAPI at
:8780, served bysystemctl --user enable fay-tmux-api.service. Routes:/canvas,/canvas/{page},/say/feed,/asks*,/stick*,/panes*,/agents,/llm/{suggest,signals},/apk/{flavor}*,/avatars/{name},/camera/upload,/crash-report. All routes JSON; CORS wide-open (local-only). - show-me — borderless Chromium artifact display at
:47777(loopback). systemdshow-me.serviceisPartOf=fay-tmux-api.serviceso they live and die together. - show-me hub-proxy —
show-me --hub-proxyon:47700(LAN/Tailscale-gated). Exposes per-agent channels by name. fay's per-agent show-me panel is the phone consumer; the roster owner is agent-tools. - fay canvas — kinetic word-by-word TTS teleprompter at
/canvas. Tails/say/feed, syncs to acoustic onsets when the entry carriesaudio_ms+onsets_ms. - Android app — build flavors drive different surfaces (default chips, mic state, Brilliant Frame OLED bridge). Background push for new Cinder decisions ships on
canary(PR #146) viaDecisionWatchService— a Firebase-freespecialUseforeground service that long-polls/decisions/watchindependent of the UI.
The Cinder outbound path
When Hei swipes a decision on the phone (/asks/{id}/answer) or types a clarify-chat (/decisions/{id}/chat with role=user), the server fires a best-effort director send of a <message from="markus"> envelope to the asking agent's pane via _deliver_to_asker in server/tmux_api.py. It targets the recorded origin_pane (%NN, from ask-markus PR #151) first, falls back to the human from, and matches the roster pane-col or name-col (PR #145).
If an answer or chat doesn't land in an agent's pane, check nudge.resolve_nudge_target first — a persona from that matches no roster column silently no-ops. The chat path had no pane delivery at all before PR #145.
Worktrees
Long-running branches live in named worktrees under ~/ht/ (e.g. ~/ht/fay-wave2, ~/ht/fay-glasses). All share the same .git under ~/ht/fay/.git. git worktree list gives the live set.
Sources
~/ht/fay/CLAUDE.md— the fay-dev role handoff.~/ht/fay/README.md— user-facing docs.