Your iPhone, tethered to your desktop's brain.
A home-screen PWA that turns your phone into a thin client for capable AI — your desktop's local models, cloud models, and (next) your own desktop agent with real tools. The phone stays thin; the brain — reached privately over Tailscale — does the work.
No backend. No App Store. No Mac in the build loop.
Your desktop is always on, and the RTX GPU running Ollama codes with models (Qwen2.5‑Coder‑class) far beyond anything a phone can. But the moment you leave the desk, that capability is stranded. iOS editors (Working Copy, Textastic, Koder) give you git and a text surface — none of them reach back into your own local inference. And native iOS dev is gated behind a Mac you may not have.
tether closes that gap: a phone-sized window onto capable AI — your desktop's model, a cloud endpoint, or (next) your own desktop agent — built entirely in web tech so it ships without ever touching Xcode. It started as a mobile GitHub editor; it's becoming a thin client for any agent endpoint (see the roadmap).
iPhone (PWA, installed to home screen)
┌────────────────────────────────────┐
│ Chat / agent surface ── HTTPS ──▶ your endpoint, over Tailscale or browser-direct:
│ • Ollama — local model (live)
│ • OpenRouter / Anthropic — cloud (live)
│ • your desktop agent — real tools ← Phase 4 · planned
│ GitHub client ── HTTPS ──▶ api.github.com (browse · edit · commit — live)
│ CodeMirror 6 · OPFS + IndexedDB (on-device cache) · service worker + manifest
└────────────────────────────────────┘
- The brain is elsewhere — a model or agent on your desktop (over Tailscale) or a cloud endpoint you choose. The phone never runs it.
- The phone is a chat client — plus a CodeMirror editor for the GitHub side.
- GitHub is one capability — browse, edit, and commit a file, browser-direct. Source of truth stays on GitHub; the phone cache is disposable.
- No server of your own — everything is browser-direct: to GitHub today, and (as the phases land) to cloud providers and your own desktop daemon over Tailscale. Nothing hosted in between.
Everything personal — your GitHub token, endpoint URLs, API keys, model — is a runtime setting entered in the app, never baked into source. Bring your own repos and your own brain.
tether ships in phases, each with a hard stop signal. Where it stands (2026-07):
| Phase | Delivers | State |
|---|---|---|
| 0–2 · Skeleton → GitHub → Chat-first agent | Installable PWA; browse/edit/commit a repo; streaming chat + read_file + diff-before-commit with your desktop model |
✅ Done |
| 3 · Multi-provider thin client | Local Ollama + cloud (OpenRouter, Anthropic) behind one Provider abstraction; pick provider+model in chat; concurrent multi-chat |
✅ Live |
| 4 · Desktop agent | A generic HTTP/SSE agent endpoint — an agent that runs its own tools; GitHub demoted to a side capability | 🔵 Planned |
The direction (D11 / D15): tether pivoted from "smart GitHub
editor" to a thin client for capable agent endpoints — local + cloud models shipped, your
desktop agent next. GitHub editing rides along as one capability, not the point. The full journey and rationale:
ROADMAP.md · DECISIONS.md · the phase specs
(2 · 3 · 4).
Vite · React · TypeScript · Tailwind (dark-first, #00FF66 accent) · CodeMirror 6 ·
a small Provider abstraction (Ollama / OpenAI-compat / Anthropic adapters) ·
vite-plugin-pwa (manifest + Workbox service worker) · static deploy to GitHub Pages.
No backend, no database.
npm install
npm run dev # local dev server
npm run build # type-check + static build to dist/
npm run preview # serve the production buildApp icons (the tether "t" monogram) are generated by python scripts/gen-icons.py (requires Pillow).
tether is single-user per instance by design — you run your own copy. Nothing personal is committed; you supply everything at runtime.
1. Deploy the static app. Fork this repo and push to main — the
Pages workflow builds and deploys automatically. One-time
setup: Settings → Pages → Source: "GitHub Actions". It serves at
https://<you>.github.io/<repo>/. The only build-time knob is the base path:
BASE_PATH—/<your-repo>/for a project site, or/for a custom domain (see.env.example).
GitHub Pages on a free plan requires a public repo. To keep it private, use GitHub Pro or a host like Cloudflare Pages.
2. Expose your desktop model (Phase 2). On your desktop, run Ollama reachable on
your tailnet and put HTTPS in front of it — a PWA served over HTTPS cannot call a plain
http:// endpoint:
# Ollama, reachable on the tailnet with the PWA's origin allowed through CORS
OLLAMA_HOST=0.0.0.0 OLLAMA_ORIGINS="https://<you>.github.io" ollama serve
# Tailscale Serve — real TLS cert on your *.ts.net domain, terminating to Ollama
tailscale serve https / http://localhost:11434Scope Ollama to your own devices with Tailscale ACLs. Full spike notes:
docs/spikes-phase2.md.
Prefer cloud, or no desktop at all? Cloud providers (OpenRouter / Anthropic — added in Settings, called browser-direct) are live (Phase 3) — skip the desktop model entirely. A desktop agent endpoint is Phase 4. See
ROADMAP.md.
3. Bring a GitHub token (Phase 1). Create a fine-grained PAT with contents read/write on just the repos you want, short expiry. You paste it into the app; it lives in on-device IndexedDB and never leaves the phone.
Deliberate non-goals — these keep the project small and the surface honest:
- ❌ A native iOS app / App Store distribution
- ❌ The phone running a model or executing code — the brain is always elsewhere (your desktop model, a cloud endpoint, or a desktop agent that has the hands)
- ❌ A hosted, multi-tenant service — tether is single-user per instance; you self-host your copy
- ❌ Accounts or real-time collaboration
- ❌ Per-language tooling beyond what CodeMirror gives for free
Early-stage and moving through the phased plan above. If you'd like to help: open an
issue to discuss before a PR, keep changes within the current phase, and read
DECISIONS.md first — it records what's locked and why, so you can
tell an open question from a settled one.
MIT © 2026 Salahuddin