Version history
Every approved write to a share's content is captured as an immutable row in the version history. The history covers content edited via:
anchorify <file>updates (CLI).POST /updates (API).- Edits from the dashboard's in-browser editor.
- Restores (rolling back to an older version appends a new
rollbackrow — the restore itself is versioned). - Approved suggestions (see Suggestions).
- Agent-edit calls (
/api/v1/agent-edit).
Every version stores the full content as it was at write time. Restoring an older version copies its content into the live share; the previous live content remains in history.
Accessing the history
Web
From the dashboard, open a share's actions menu (⋯) → Version history. The page lists every approved version newest-first, with author, timestamp, source (publish / rollback / suggestion / agent_edit), and byte count. Click any row to:
- View the version's full body (read-only).
- Diff against the current version — a line-by-line comparison.
- Restore — make the older version the live content.
API
The full surface lives under /api/v1/shares/:id/versions/*:
GET /api/v1/shares/:id/versions— paginated list, newest first.GET /api/v1/shares/:id/versions/:vid— fetch one version with its body.GET /api/v1/shares/:id/versions/:a/diff/:b— line diff between two versions.POST /api/v1/shares/:id/versions/:vid/restore— restore.
All four require cookie-session auth as an admin of the share's owner org. Per-user CLI tokens don't yet expose the version surface (this is a follow-up).
Diff format
The diff endpoint returns a flat list of line-keyed entries:
{
"from": {"id": "...", "created_at": 1717400000000},
"to": {"id": "...", "created_at": 1717449600000},
"lines": [
{"kind": "equal", "text": "# Q1 report"},
{"kind": "remove", "text": "Looks great."},
{"kind": "add", "text": "Looks great. Updated 5/15."}
]
}
Lines are computed with a longest-common-subsequence diff. For very large or binary content, the diff falls back to {"truncated": true, "lines": []} with a reason field — the dashboard surface shows a "view both versions side by side" link in that case instead of attempting to render the diff.
Restore semantics
Restoring version V_old does NOT delete any newer versions. The flow is:
- The current
shares.contentis copied intoV_old.content(this is a no-op sinceV_oldis what we're restoring to). - A new version row is appended to history with
source='rollback'and the same content asV_old. The rollback itself is versioned. shares.content(andfilename,content_type) flip toV_old's values.- A
share.restoreaudit event lands on the owner org's audit feed.
The previously-live version stays in history — you can restore back to it just like any other.
Version status
Each version has a status of approved, suggested, or rejected:
approved— the version is or once was the live content. Includes allpublish/update/rollback/agent_editsources, plus suggestions that were approved.suggested— an open proposed change. Not reflected inshares.contentuntil an admin approves.rejected— a proposed change that was turned down. Kept in history for audit.
The dashboard list collapses rejected rows by default; pass ?status=approved to the list endpoint to hide suggestions entirely.
What's not in here
- Branching / multiple parallel versions — there's one linear history per share.
- Per-line annotations — comments attach to the whole share, not to a diff line.
- History deletion — there's no way to scrub an old version from history. If a version contains material that must be deleted, contact the operator.