Branching Text Generation in Obsidian

LLMs TypeScript Projects

Most interfaces to a language model are a chat box: you type, it replies, the reply scrolls away, and the branch you didn’t take is gone. But generation is fundamentally a tree. At every step the model samples one continuation out of many, and the discarded branches are often more interesting than the one you kept. I wanted an interface that treated writing with a model as exploring that tree, not reading a transcript.

Obsidian’s Canvas felt like the right surface for it. Canvas gives you cards on an infinite 2D space with arrows between them — which is to say, it gives you a graph for free. So I wrote a plugin, archnet, that makes the Canvas into a branching text generator.

How it works

You select a card on the canvas and press Cmd + D. The plugin walks upstream through the graph — every card that feeds into the one you selected — aggregates that text into a single context, and asks the model for completions. Each completion comes back as a new child card branching off the one you started from.

The upstream-aggregation bit is the key idea. Because context is gathered by following the arrows backwards, you can compose prompts spatially. Put a system instruction in one card, some examples in another, your draft in a third, wire them all into a node, and generate from there. Rearranging the graph rearranges the prompt. Branching from an earlier card explores a different path without throwing away the one you already have.

It’s the loom pattern — non-linear, tree-structured interaction with a model — built on top of a tool I already lived in. The plugin took its cues from the worldspider VS Code extension and adapted the idea to Obsidian’s canvas.

Setup

It talks to the OpenAI API, so you drop your key into the plugin settings (from platform.openai.com) and you’re away. Select a card, Cmd + D, watch the branches grow.

Why I built it

This was 2023, GPT-3.5 and GPT-4 were new, and the dominant metaphor for using them was already calcifying into “assistant in a chat window”. That metaphor quietly throws away the thing that makes sampling interesting: you only ever see one roll of the dice. A graph interface keeps all the rolls around and lets you curate them.

It stayed a work-in-progress, but it changed how I think about model interfaces. The chat box is a convenient default, not a law of nature, and there’s a lot of room left in how we let people steer generation rather than just what the model can generate.