docsconcepts
fork the whole memory, try a direction, diff it three-way, merge what won. and the one rule that keeps trunk readable.
6 pages

branches & history

Code has had branches for decades. Thinking hasn't. innernet gives a memory the same two tools: branches, for holding two versions of an idea on purpose, and history, for knowing how the current version came to be.

the one rule on trunk#

A dimension body describes the present. When something is superseded, netti replaces it in the body and appends one dated line under ## history at the end of that dimension:

markdown
## history
- 2026-09-12 — pricing: was a flat $12 seat → now usage-based, $0.005 per 1k ops
- 2026-08-18 — storage: was a local store → now one hosted memory

At most twelve lines stay in the ledger; the commit log keeps the rest. Retrieval leaves history out of focus unless the ask is about the past (retrieval), so trunk always answers with one truth.

when to branch#

Branch when you want two truths at once: a different positioning, an alternative architecture, a pricing experiment, a rewrite you might abandon. Divergence lives on branches; trunk stays unambiguous.

the lifecycle#

  1. Fork. innernet_branch_new { project_slug, name, summary } snapshots every dimension and node at the current head into an overlay.
  2. Work on it. innernet_save_context { slug, branch: "name", dimensions: … } writes to the overlay only. Trunk is untouched, and so is everyone reading trunk.
  3. Compare. innernet_branch_diff is a three-way diff against the fork point: what the branch added, modified and removed, and conflicts, the pages trunk also changed, differently, since you forked.
  4. Decide. Merge it, park it, or keep going.

In a conversation you rarely call these by name. Say it:

text
Branch my-product as "usage-pricing" and rewrite the pricing page there
as usage-based. Then show me what changed against trunk.

merge, three ways#

innernet_branch_merge applies only what the branch changed. A branch with no edits is a no-op. An edit trunk made after the fork is never overwritten. A page both sides changed differently stays as trunk has it and is listed under diff.conflicts; the result says merged: false until you resolve those pages and merge again. A merge records its own commit and moves the head.

A parked branch, or one already merged, refuses to merge.

park, revive#

innernet_branch_park { name } archives a branch with its overlay intact. park: false brings it back. Nothing on a parked branch is lost; it just stops showing up as live.

over REST#

bash
POST  /api/v1/projects/{slug}/branches                      # fork
PUT   /api/v1/projects/{slug}/branches/{name}/dimensions/{d} # write to the branch
GET   /api/v1/projects/{slug}/branches/{name}/diff           # three-way diff
POST  /api/v1/projects/{slug}/branches/{name}/merge          # merge
PATCH /api/v1/projects/{slug}/branches/{name}  {"status":"parked"|"active"}
GET   /api/v1/projects/{slug}/commits                        # the log

Examples with full bodies are on the API page.

commits#

Every save, capture, fold and merge is a commit with a hash, a parent, a message and a trigger (genesis, mcp, api, fold, merge…). The log is append-only. It is what lets a dimension stay short: the body says what is true, ## history says what changed recently, and the commits say everything else.