Workspace
The workspace is a drive-like tree of files and folders, scoped per namespace, where every file write produces a new immutable revision in an append-only chain. Mutations use optimistic concurrency control (OCC) — you pass the version you think you’re editing, and a stale guess is rejected with a conflict instead of silently overwriting.
The drive tree
Section titled “The drive tree”A WorkspaceItem is either a file or a folder (src/workspace/types.ts:6-9). Folders
nest via parent_id, so items form a tree inside one namespace. Each item carries a
monotonic version (starts at 1, types.ts:16) and, for files, a pointer to the latest
revision:
| Field | Meaning |
|---|---|
kind |
file or folder |
namespace |
the drive this item lives in |
parent_id |
enclosing folder (absent = root) |
version |
OCC counter, bumped on every item mutation |
current_revision_id |
latest revision (files only) |
current_revision_number |
revision count (files only) |
deleted_at / deleted_by |
set on soft-delete; IDs and history preserved |
Deletes are soft — workspace.delete_item soft-deletes the whole subtree, preserving
IDs and revision history (workspace.ts:295-313).
Immutable revisions
Section titled “Immutable revisions”A file’s content lives in WorkspaceRevision rows, not on the item. Each revision is
written once and never mutated (types.ts:36-47): it has a revision_number, a
previous_revision_id linking it to its predecessor, a storage_key pointing at the
backing blob, and size_bytes / content_type. Writing a file appends a new revision and
re-points current_revision_id; the old revision stays addressable. workspace.list_revisions
(HTTP GET /workspace/items/:id/history) walks the chain.
Text content is gated by isTextContentType (src/workspace/utils.ts:18-27) — only
text/* plus json/javascript/typescript/xml/yaml/markdown content types go through the
text read/write commands (workspace.read_text / workspace.update_text). Anything else
is binary.
Optimistic concurrency (OCC)
Section titled “Optimistic concurrency (OCC)”There are two OCC tokens, one per kind of mutation:
- Item mutations (
update_item,move_item,delete_item) requireexpected_version(workspace.ts:120-134). The store compares it to the item’s currentversion; a mismatch returns aconflictresult, surfaced as HTTP 409 (workspace.ts:75-85,257). - Text writes (
update_text) requireexpected_revision_id— the id of the revision you read (workspace.ts:145,176). If a concurrent write moved the head, you get a revision conflict (409,workspace.ts:414,517).
read item v3 ──► edit ──► update_item(expected_version: 3) │ head still v3 ─────────┼──► ok, item → v4 head now v4 ─────────┴──► 409 conflict (re-read, retry)The mutation result is a discriminated union — ok | not_found | conflict | deleted
(types.ts:102-112) — so callers can branch on the outcome rather than catching an
exception for the expected-version case.