
Branch
Think in branches, not threads.
Project Overview
Branch is an AI canvas where every question fans out into several answers, each from a genuinely different angle. You follow the ones worth following, merge the good parts, and keep a map of how you got there. It runs on a local AI model on your own PC, with optional Claude API deep research when you want the web.
Why It Exists
Real thinking branches, so I built a canvas where the thinking can branch too. Four problems with chat apps shaped the design.
One answer, one line
Chat apps give you one answer in one line.
No way back to a fork
Real thinking branches. You want to compare approaches, chase one, drop another, and come back to a fork later.
Same question, same answer
Asking the same question twice mostly gets you the same answer reworded. Branch plans the differences up front, so each answer earns its place.
Everything sees everything
Long conversations get muddy because everything sees everything. In Branch, each line of thought only remembers its own path.
What It Does
Fan out. Ask a question and pick 1-5 branches. The AI picks distinct angles, such as "Cost-first", "Step-by-step", or "Critical take", and writes one answer per angle. Each answer is a card on a pan-and-zoom canvas.
Route pills. Under every answer sit 3 small pills with suggested next moves, like "Walk-run schedule" or "Overcome resistance". One click asks that question and fans out again. Routes you have taken show a ✓.
Follow up anywhere. Hover an answer and press + for a new question square, at any depth, on any branch, including old ones.
Merge. Pick 2-5 answers from anywhere on the canvas and combine them into one, or compare them side by side. Merged answers can be followed up too.
Read in full. Click any card to open the answer in a side panel, with breadcrumbs back to the root.
Summarize the path. One click writes up the question, the direction taken at each step, the angles not explored, and where it landed. Export it as Markdown.
Boards. Everything saves automatically in the browser. Switch between boards and pick up exactly where you left off, view position included.
Deep Research Mode
Optional, and it uses the Claude API. Pick a Claude model in the model picker (Claude Opus 5.5 by default). All angles of a fan-out research at the same time. Each one searches and reads the web, cites its sources, and uses adaptive thinking.
Spending cap. Default $5 per fan-out, covering every angle together, plus a live usage monitor with tokens and cost per board, per month, and all time.
Bring your own project. Point it at a folder of papers, notes, PDFs, and Word files. It is indexed locally, and only the passages relevant to each question are sent with the request.
Key stays local. Your API key stays on your PC, server-side. The browser never holds it.
Cheap to explore. Route pills and summaries still use the free local model.
How It Works
Generation runs in two stages, then the canvas takes over.
1. Planner. One short call with a JSON schema returns N angles, each a label plus an instruction. The result is validated, retried once, then falls back to fixed angles.
2. Writers. One streaming call per angle. Each writer gets only the path from the root to its question. Siblings are never included, and a unit test enforces that.
3. Follow and merge. Any answer can start a new fan-out, and any 2-5 answers can be merged into one. Each new fan-out sees only its own ancestors.
What each writer sees
root question |- angle A sees: root | `- follow-up sees: root, A `- angle B sees: root angle B never sees angle A
Architecture at a glance
Branch (React canvas in the browser)
| same origin, 127.0.0.1 only
v
Small local Python server (FastAPI)
|- /ollama -> Ollama (qwen3:14b), local GPU
|- /api/claude -> Anthropic API (optional;
| key held here, usage
| logged, cap enforced)
`- project index -> local embeddings of
your files (nomic-embed-text)Tech Stack
Front End
React 18 and TypeScript, built with Vite. React Flow for the canvas (pan, zoom, custom nodes, minimap). Zustand for state, Dexie over IndexedDB for saved boards. zod validates the AI's structured JSON. react-markdown renders answers, only in the reader panel.
Local Server
A small Python server (FastAPI), same origin, 127.0.0.1 only. It proxies Ollama and the optional Anthropic API, holds the key, logs usage, enforces the cap, and indexes project files locally with nomic-embed-text.
Models
Local: Ollama running qwen3:14b on the PC's GPU. Cloud, optional: the Claude API through the official Python SDK, with the web search and web fetch tools and automatic retry on refusal.
Design Decisions
1. Branches are independent. A follow-up sees only its own ancestors.
2. Real variety, not repetition. Angles come from an explicit plan, not resampling.
3. Local first. The default model runs on your machine for free. The cloud is opt-in, with its cost shown.
4. Light when idle. No polling and no background timers. Streaming text reaches the screen at most every 80 ms, and off-screen cards are not drawn.
5. Glanceable. Cards show an angle and a short preview. The full text opens on demand.
Layout. A custom fan layout: the root's answers ring it in a full circle, and later fans open in arcs of up to 180° facing away from their parent. A collision pass then pushes overlapping subtrees apart. Drag a card to pin it, and Tidy re-lays everything.
By the Numbers
The figures I tracked while building it.
60 fps
panning a 300-card canvas
~48 MB
of tab memory on that canvas
225 KB
page bundle, compressed
~1 min
for a 3-angle local fan-out on a single consumer GPU
0
timers or animation frames running while idle
33
TypeScript tests, plus Python tests for the research back end that use a faked Claude, so testing costs nothing
Bugs and Lessons
The problems that taught me the most while building it.
"3 different answers" gives near-duplicates
A planner step that names the angles first gives real divergence, plus readable labels.
A radial layout fell apart on real trees
Weighted by leaf count, it looked great on balanced trees and terrible on real ones, where people dig deep on one branch. The first ring got pushed out 4,700 px. Local fans plus a collision pass fixed it.
Fit-to-view broke for new cards
React Flow does not draw cards it has not measured yet. Giving every card an initial size fixed it.
The merge bar covered the answers
It sat on top of the very answers you were trying to pick. Recording the demo video is how I found that bug.
The planner offered one angle too many
Structured outputs cannot enforce an exact array length, so the extra angle triggered the fallback to generic angles. It now keeps the first N.
Culling broke the demo recorder
Off-screen culling meant the recorder's "wait for 5 answers" check failed, because the earlier answers were no longer on the page to count.
Key Takeaways
Variety came from planning, not from sampling harder. Naming the angles first gave answers that actually differ, and labels people can read at a glance.
Keeping each branch's context to its own path kept long explorations clear, and a unit test keeps it that way.
Making local the default kept exploring free and private. The cloud is there when the web is worth the cost, and the cost is always visible.
Links
Branch runs locally and does not have a public link yet.