$ ls articles | grep * # 39 found
Timothy Part 26: One Terminal Event and Five Ways to Lose It
A slow model on a CPU-only box made streaming chat turns vanish with zero trace: no assistant message, no error, no evidence the turn ran. Five commits trace one causal chain, defending a single contract in the gateway: a stream ends with exactly one terminal event.
Timothy Part 25: Routes as Roles, Not Names
Routing used to be 7 frozen route names compared by string literal across the gateway and brain. Now a capability column and a role column decouple what a route does from what it is called, routes are user-managed from the settings panel, and the headline feature shipped unreachable through the public API for a few hours because the proxy allowlist and the gateway endpoints live in different files.
Timothy Part 24: An Orange T and a One-Line Install
Two commits landed twenty-five minutes apart on the same morning: one gave Timothy a face by rotating the brand accent from purple to a tabby-orange T mark, and one made it installable without cloning the repo, through a release pipeline, a prebuilt-image compose file, and a magic-link sign-in.
Timothy Part 23: Hand-Built Charts and a Faster CI
The analytics dashboard's charts came from recharts and looked it: flat bars, no hover, no way to isolate a series. I replaced them with a small set of hand-built SVG chart primitives, and while I was in the CI file anyway, fixed the bigger problem of every PR paying for a full test suite it didn't need.
Timothy Part 22: Connector Sensitivity and a Same-Day Bug
Part 18 pinned a session to a local model the moment it touched Gmail specifically. This part generalizes that floor to any connector I flag sensitive in settings, and tells the honest story of shipping it, missing the mid-turn case, and fixing it the same day.
Timothy Part 21: PDF Attachments and a Turn That Outlives the Request
Timothy can now read PDFs, converted to markdown once at send time instead of on every turn, and a chat turn no longer dies just because the browser tab that started it went away. Both fixes trace back to the same instinct: a turn belongs to the session, not to whatever request or conversion happened to kick it off.
Timothy Part 20: Ears and Eyes, Voice Input and Image Attachments
Timothy can now hear and see: a microphone button transcribes speech entirely on-box through a self-hosted Whisper sidecar, and the composer accepts image attachments that are stored content-addressed on the brain and routed to a dedicated vision chain. Both are input-only for now; the model still cannot speak back or generate an image.
Timothy Part 19: A Chat That Survives Reloads and Races
The event log from parts 6 and 7 made turns durable on disk, but the live chat above it still lied under ordinary failure: a reload mid-answer looked stuck, a dead turn looked like a stuck spinner, and parallel tool calls could stack duplicate prompts. This post covers the milestone that made the live experience as honest as the log underneath it: reattach across reloads, one turn per session, persisted permission asks, and turns that say plainly when they produced nothing.
Timothy Part 18: Sensitive Sessions Stay Home
Some content should never reach a cloud provider, no matter which model is smartest. I added a sensitive-tool route that pins a session to a local model the moment it touches something like Gmail, made the pin sticky across every later turn and side-call, and moved local inference off a containerized Ollama onto a native host runner so it's actually fast enough to use.
Timothy Part 17: Mission Schedules, Notifications, and the Canary
A mission that never gets scheduled again is barely different from a chat message. This post covers the cron scheduler that fires mission templates, transition notifications pushed over SSE, per-mission spend read honestly off the cost ledger, an opt-in escalation route for stuck missions, and the golden-mission canary that gates every change to the harness.
# ---