~3 min read
Cockpit — fomo.cagatay.my·
One screen. The agent is the spine; everything else is its face, its hands, and a red button.
read · joints 0.1 s, then the answer — folded, board on the bench, 0.11 m ahead. Real capture, real turn.fomo dash runs FastAPI on 127.0.0.1:8091. It owns the serial port: one process per adapter,
so the tools go through it whenever it is up. It boots with no arm attached and hot-attaches the
bus within ~2 s of the adapter appearing (Arm watcher).
The screen·
One screen, the agent is the spine. Top bar: a tally light that says what Fomo is doing
(idle / thinking / talking / moving), status pills (bus, rail voltage, torque, pose, eyes, link
period), a big red STOP (/api/control/stop, always in reach, also on the phone with the dock
open) and ⚙ settings. Face on the left: the eyes (live MJPEG, tap to start, fps · watchers) and
the digital twin, following the servos at 5 Hz. Talk on the right: the log and the composer.
On a phone (< 900 px) the face sits on top behind an eyes/twin tab, the composer is pinned above the
home indicator, and the twin's 590 KB of three.js is not even fetched until the twin tab is opened.
The log is the narrative, not a chat window bolted onto a control panel. Your prompts, Fomo's
streamed answers (first-token latency shown), and every tool call as a row in words —
move · elbow → 200.5°, look · pan +30°, pose · go home, motion · happy · 40°/s, photo
(the picture inline) — with its duration, and a progress bar while a motion plays (state.busy =
motion:happy 3/7). Errors come back in words too: the guard's {'wrist_flex': 21.2} deg behind
reads wrist_flex 21.2° behind the goal, a stall says whether the arm folded itself afterwards.
Manual actions land in the same log as notes ("moved elbow to 200° · 0.8 s · 3 legs"), so the agent
and you share one story; the agent's next turn sees them.
d. Sliders sit on the measured windows (base 66–251°, elbow 69–262°), every pose and motion is a button, STOP is in the corner too.Drive by hand — 🎚 or d — is a dock (a bottom sheet on the phone, above the composer): one
slider per joint bound to its measured window, look buttons (pan/tilt), fold + every pose, every
motion (/api/motions, one button each, disabled while busy), torque on/off, a speed slider capped at
the guard's 90 °/s. Sliders move on release, never while dragging. Nothing bypasses the guard.
Voice — 🎤 or m — is browser-native: SpeechRecognition types into the composer and sends the
final phrase; 🔊 reads finished answers with speechSynthesis. No keys, no server, so it works only
where the browser has it (Safari, Chrome). While you talk, the thinker holds back.
Thinker — the think toggle in the bar (/api/agent/thinker, off by default, stored in
~/.fomo/agentic.json): every every_s seconds Fomo takes one photo, reads its state and says one
line about what it sees, streamed over /ws/thinker into the log as a thinking turn. It never moves
joints 1–4; with may_move it may pan/tilt to frame. It skips a tick while the arm is busy, while
you are typing or talking, and past its hourly budget.
Settings (⚙) hold the panel key, the thinker's cadence, the agent's prompt and model; the panel installs as an app and says "offline — the arm is not reachable" instead of a blank page.
Every route, the auth chain, sim mode and the launchd/cloudflared recipe: Reference.