Skip to content

Branches and file history

Files and directories have stable object_id values. An edit creates a file state; a rename preserves the object’s identity and history. A workspace commit records a consistent filesystem view. User KV stays disk-wide and is excluded from commits.

Files, entries, stat, mkdir, move, history, restore and exec accept one optional query selector:

Selector Behavior
Omitted Live main.
branch=NAME Independently writable branch.
commit=UUID Read-only committed filesystem.
label=NAME Read-only commit or directory pin; a pinned directory appears at /.

Supplying several selectors returns 400. A write to a historical view returns 403. JS, nested bash() and qjs share the selected view. Read a file pin with GET /label-content?name=NAME.

All route suffixes below start at /v1/disks/{disk}/.

Method Suffix Input and result
GET stat?path=/log.txt Current metadata, including object/version IDs, revision and edit timestamps.
POST mkdir?path=/notes&recursive=true Create a directory; 204.
POST move JSON {"from":"/a","to":"/b"}; exact destination; 204.
GET / POST branches NDJSON list / JSON {"name":"work","from":"COMMIT_UUID"}.
DELETE branches?name=work Remove a nondefault branch; 204.
GET / POST commits NDJSON list / JSON {"message":"daily","label":"daily"}; POST accepts branch.
DELETE commits/UUID Remove an unreferenced commit; 204.
GET history?path=/log.txt Newest-first NDJSON {metadata, sealed} including inherited base history.
GET versions/UUID Exact sealed file bytes.
POST restore JSON {"path":"/log.txt","version":"VERSION_UUID"}; publish a new file state.
GET / PUT labels NDJSON list / JSON {"name":"keep","path":"/log.txt"} or {"name":"keep","commit":"COMMIT_UUID"}.
DELETE labels?name=keep Remove a pin; 204.
GET label-content?name=keep Pinned file bytes.

Branch and label names contain 1 to 255 bytes without control characters. Names use query/JSON values, so normal URL encoding applies. Deleting a commit used as a branch head, base, parent or label returns 409. File/directory pins and commits remain until explicitly deleted. Move replaces a file or empty directory of the same kind; moving a directory into itself or beyond the path limit fails before publication.

Create a workspace commit
curl --fail-with-body -X POST "https://api.wabe.sh/v1/disks/demo/commits" \
-H "Authorization: Bearer YOUR_PROJECT_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"message":"before edits","label":"before"}'

The response includes id, branch_id, revision, root_directory_id, parent/base commit IDs, created_at_ms and message. Pass its id as from to POST /branches, then add ?branch=work to file or execution requests. A commit seals that branch’s drafts; other branches continue independently.

New disks use autosave_interval_ms: 0, recording every completed edit. Set a nonzero interval through storage configuration to group rapid edits into one mutable draft. The window starts with its first edit, rather than restarting after every edit. At 10,000 ms, an edit after the window seals the prior version and creates a new draft. There is no timer-created version for an idle file.

Drafts keep the same version_id while their revision and last_edit_at_ms change. Commits, pins and eviction seal them. A sealed version is immutable; subsequent edits create another history point. Restoring file content creates a new state and reuses its immutable content.

history_retention_ms: null preserves all intermediate history. A duration trims old intermediate versions during GC; zero preserves only states needed by live branches, commits, labels and retained notification captures. A commit’s content remains readable after intermediate file history is trimmed.

PUT and append accept expected_id=VERSION_UUID&expected_revision=N together. A stale precondition returns 409. Restore accepts the equivalent optional JSON expected_version: {id, revision}. Retrying an append can duplicate bytes; a missing response after publication leaves an uncertain acknowledgement outcome.

400 for invalid selectors, paths, names or types; 401 for authentication; 403 for historical writes; 404 for missing state; 409 for stale versions, conflicts or referenced objects; 500 for storage/corruption failures. Stream failures after HTTP headers terminate the body.