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:
## 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 memoryAt 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#
- Fork.
innernet_branch_new { project_slug, name, summary }snapshots every dimension and node at the current head into an overlay. - Work on it.
innernet_save_context { slug, branch: "name", dimensions: … }writes to the overlay only. Trunk is untouched, and so is everyone reading trunk. - Compare.
innernet_branch_diffis a three-way diff against the fork point: what the branch added, modified and removed, andconflicts, the pages trunk also changed, differently, since you forked. - Decide. Merge it, park it, or keep going.
In a conversation you rarely call these by name. Say it:
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#
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 logExamples 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.