Inspiration
Most productivity tools assume the hard part is remembering what to do. For a lot of people, especially those with ADHD or burnout, the hard part is starting. You know the task, you open the tab, and then nothing happens. [Add one sentence about why this matters to you, such as a time you got stuck or someone you know.] I wanted a tool that meets you at the moment you stall, without asking you to manage yet another list.
What it does
Tether is a Chrome side-panel extension that shows one small step at a time. It watches only for activity and tab focus, never page content. When you go idle or wander off to another tab, it doesn't assume anything, it asks: "Are you stuck, or taking a break?" If you say "still working", it waits longer next time (up to 8x), so a wrong guess makes it quieter. If you say you're stuck, you describe why in your own words, a local model sorts it into one of five blocker types (credential, knowledge, external dependency, overwhelm, distraction), and Tether puts one action of 20 words or fewer in front of your task. Finish it and you're back on track. Everything runs on your machine.
How we built it
- Flow: a deterministic XState state machine (idle, planning, executing, friction detected, diagnosing, resolving), with unit tests for the flows and the patience back-off.
- Sensing: a tiny content script sends a timestamp pulse at most every 2 seconds, plus focus state. No keystrokes, no URLs, no page text.
- AI: Ollama with llama3.2:3b, used at only two points: breaking a goal into steps and classifying a blocker. Output is validated against a JSON schema and user text is sanitised.
- Fallbacks: every model call has a non-model fallback (keyword rules), so Tether still works if Ollama is down.
- Stack: TypeScript, Bun monorepo, React, XState, Vite, Chrome Manifest V3, Ollama. CI runs typecheck, tests and build, and tagged releases ship a built zip plus a no-install demo build.
Challenges we ran into
- Idle is not the same as stuck. Reading and thinking look like stalling. The fix was to ask instead of assume and add the patience back-off.
- Keeping the model out of the control flow. A small model is unreliable, so the state machine decides what happens next and the model only fills in two narrow slots.
- Ollama rejecting extension origins. Requests from the extension were refused until I added a request-header rule scoped to the extension's own calls to Ollama.
- Cold-start latency. The first answer from a small model on CPU can take a long time, which meant tuning timeouts and warming the model.
- Install friction. Local AI means a setup step, so I built a demo build with canned answers that works in 30 seconds.
Accomplishments that we're proud of
- A genuinely private design: the only network access is 127.0.0.1, and the content script never reads page content.
- A reproducible eval: 93% accuracy on 30 labelled blockers, with the misses documented in the README.
- Graceful degradation at every layer, so there is no dead end when the model fails.
- A test suite, CI, tagged releases and a one-click demo build for judges.
What we learned
- Constrain the model: validated schemas and deterministic fallbacks made a 3B model usable.
- For a stuck user, asking is better than guessing, and a tool that learns to be quiet is more respectful than one that nags.
- Privacy is a feature when your users already feel watched, and local-first changes what you can promise.
What's next for tether
- Publish to the Chrome Web Store and add Firefox support.
- Learn per-user timing, so nudges adapt to how you actually work.
- Grow the eval set beyond 30 cases and test other small models.
- Run informal user tests with people who have executive dysfunction, and use their feedback to refine the steps.
- A full accessibility audit of the panel (keyboard use, reduced motion, screen readers).
Built With
- bun
- chrome
- github-actions
- llama-3
- local-first
- manifest-v3
- ollama
- on-device-ai
- react
- typescript
- vite
- vitest
- xstate
Log in or sign up for Devpost to join the conversation.