The Folio Schema
The settled shape of the unified Folio storage — six recursive tables, twenty-nine binding constraints with their owner rulings, the printed About card grammar, the six-pillar review lens, and the two stages (proposals and Goldie; docs made wholly Current) that Backlog tasks still own.
Decision
The three-tier content schema (documents / modules / blocks, each with
its own version table) is replaced by one recursive folios table, one
folioVersions table of explicit save points, folioPins carrying containment
order, libraries and libraryPins for the shelf, and a tags vocabulary.
Six kinds share one drawer; only blocks carry material; the About card is the
authored surface. This record is the durable statement of that shape and of
the constraints every stage of the build was held to. The two plans that
carried the work are retired; what remains unbuilt is owned by Backlog tasks
named in the Gap below.
In plain terms: the filing cabinet used to have three drawers of nearly identical cards, so every rule about labels, dividers and cross-references had to be written three times. Now there is one drawer, each card says what sort it is, and the rules are written once. This page is the settled description of that cabinet and the rulings made while it was built. It is not a to-do list; the unfinished pieces are tracked as tasks.
Current — the storage shape as it stands
This is what convex/schema.ts declares today. The six legacy tables and the
interview audit table are deleted; both seeded corpora compile straight into
these rows.
folios — the card in the drawer. key; kind (one of six:
workspace, project, document, module, content_block, data_block);
parentFolioKey (absent on a root); handle and optional label; owner;
derivedFromFolioKey / derivedFromVersionKey (same-kind lineage);
headVersionKey (the open live draft); routeKey (a card with one opens as a
page); workingRevision (root Documents only — the proposal baseline);
placeholderHandle; externalSyncSource / externalSyncId; deletedAt.
Indexes: by key, by parent, by parent and handle, by kind and handle, by route
key, by derived-from folio, by owner and kind.
folioVersions — one save point of one folio's own content. key,
folioKey, versionNumber, previousVersionKey, restoredFromVersionKey,
createdBy, creationMethod, versionStatus (sealed or live draft); the
envelope columns guide, tags, access; file_name (declared, unread —
owner ruling 2026-09-09: download names derive from label and version);
changeNote, editedAt; and payload, present only on blocks and validated
by kind. Indexes: by key, by folio and version number, by folio and version
status.
folioPins — the save point's schedule. parentVersionKey,
childFolioKey, childVersionKey, order. A parent edition's pins say which
exact child editions, in what order, that save point comprises. Position lives
nowhere else.
libraries and libraryPins — the shelf and its filing slips. A library
has key, label, type (public / personal / group) and an optional
ownerUserId. A pin names libraryKey, folioKey, the exact
folioVersionKey, optional sourceOrder / sourceSiblingMax, and
retiredAt. No product writer exists yet; the internal publishToLibrary
primitive is the only writer.
tags — the controlled vocabulary. key, type, value. No product
writer yet.
Every stored member is typed — no v.any() in the envelope or the payload.
The payload validators derive from the domain's About-card schemas, so the
card's type and the column's validator are one statement. The read and write
contracts, the executor catalogue and the working-revision rule are described
on the Folios schema page.
Settled constraints
Binding on every stage; the numbering is the one the build used, so an older commit message or task comment that cites "constraint 19" still resolves.
folios.kindis the sole kind discriminator. Block nature iscontent_blockordata_block, never a secondtypeswitch.- Only blocks carry
payload; containers have none. - A child has one stable parent folio. A parent version's pins state which exact child versions, in what order, that save point comprises.
- Position exists only on
folioPins.order; it never prints and Goldie never authors it as a raw scalar. - Derivation is same-kind and records source folio and source version.
- Every edit patches an open live draft. A version is created deliberately.
- Saving a container seals changed descendants bottom-up, reuses unchanged sealed editions, and seals the container against a fully sealed schedule.
- Save Version always appends a checkpoint for the explicitly saved folio; unchanged descendants reuse their latest sealed editions (GB-196).
- Progress derives from the fields; nothing stores a status. A field is done
when it holds a value or is
skipped;skippedis settable only whererequiredis false;completemeans every applicable field is answered or skipped (2026-09-02). reuseType,reuseTypeSnapshot,uiMode, the payment/generation cluster, legacy display/flow inheritance anddocumentLifecycleare not migrated.- The About card prints
identity,guide,tags,access, thencontentordata. Position and children never print. - Stack v3 is the one live compound shell. Storage migration changes its inputs, not its anatomy. A table change does not earn a new Stack version.
- One executor per operation-catalogue row, for every kind, through the
shared prologue; the one per-kind branch is the keyed payload union.
write-document-guidekeeps its own row. - Access rules are kind-agnostic (owner, 2026-09-02): every
accessmember follows one rule whatever the folio's kind. Since the per-folio lock retired on 2026-09-11, the rule governshidden_forand what follows it. - A lock never binds a Builder (owner, 2026-09-02) — moot since 2026-09-11: there is no lock.
- Prefer existing packages over hand-rolled code (owner, 2026-09-02): the
prologue is a
convex-helperscustomMutation, the field contract is one zod schema, collaborative block text is@convex-dev/prosemirror-sync(GB-174, still open). The operation rule book and the folio tree stay hand-rolled: they are the product's own rules. - No dual-write, ever. A unified handler never touches a legacy table.
- A control is offered on every kind unless a rule withholds it, and the
rule is a fact rather than a kind test.
FOLIO_SCHEMA_CONTAINMENTis the one table that says what sits inside what; the operation catalogue reads it rather than re-deriving it. - Remove is offered where a folio is shown as a child, never where it is the subject (owner, 2026-09-04): you cannot remove the card you are standing inside. The deciding fact is the parent in the view, not the kind.
- Remove and Delete are different families and both apply to every kind. Remove changes the parent's schedule; Delete marks the folio itself, reversibly, and takes it out of search. Nothing is destroyed.
- If real user data or a production deployment is discovered, stop: replace-and-reseed is no longer authorised and the work is replanned as a widen–migrate–reconcile–narrow migration with backup and rollback.
- Saved versions are immutable; restore continues linear history (owner, 2026-09-06, GB-196; Sealed Versions Are Immutable). Only the working draft is editable; restore appends the selected state as the next checkpoint.
- Delete is a Folio fact, not a placement (owner, 2026-09-04; Delete Is a Folio Fact). A deleted Folio leaves the live canvas and every newly sealed schedule, keeps its live pin for Put back, and older editions are never altered.
- The About face writes identity and guide (owner, 2026-09-06; The About Face Writes Identity and Guide). A block's material is edited on its own face; Goldie keeps her own door to numbering and conditions.
- Duplicate copies the live draft, whole and fresh (owner, 2026-09-06; Duplicate Copies the Live Draft). Recursive; collected answers cleared; handle takes the next free suffix and the name gains " (copy)"; lineage recorded.
- Root Documents are created through an interim browser door (owner, 2026-09-06; Root Documents Are Created Through an Interim Browser Door). The one public write without a session; sign-in deletes the door.
- The Document's working revision is the proposal baseline (settled
2026-09-06). The root Document row carries a monotonic
workingRevision; every material transaction advances it exactly once through the operation builder; filing records it and acceptance compares and advances it atomically, refusing asstalewhen it has moved.folio/documentRevision.tsowns the rule;runFolioTransactionis the seam acceptance composes on. - The canvas is one screen for every kind, and depth is a fact (owner, 2026-09-07; The Folio Canvas Shows a Listing). A child with a route key is a card; one without opens in place. Home is the canvas of the session's binding.
- Insert from library is one operation with two doors (owner, 2026-09-07;
addendum to A Library Is a Shelf).
Post-MVP; constrains the
sourceseam Stage E leaves open, nothing more.
The printed About card
The About YAML is the user's authored card and Goldie's read/write surface for facts about the folio. The grammar:
- Sparse. Optional and empty members are omitted — absence means "not set", never a manufactured default. Absent groups are not printed empty.
- Booleans print as yes/no; collections print as lists; negative entries are never manufactured.
- Children never appear — no
modules:orblocks:arrays. - Neither
positionnororderprints; the wordpayloadnever prints — a block's material prints as itscontent:ordata:wrapper, last. guide:prints directly underidentity:on every kind.- Stored
kindprints asfolio_kind. libraries:lists the Libraries holding the folio, by label, printed from its active Library entries (owner, 2026-09-29). It is read-only: an edit to it is ignored, not refused, because membership changes only by a deliberate save from Publish to Libraries › (libraries.mdx). A folio on no shelf prints nolibraries:line.- The owner prints as the last member of
tags:,owner:with their name as the listed cards show it (owner, 2026-09-29), not underaccess:by account key. Read-only, likelibraries:: an edit is ignored. An owner with no stored name prints noowner:line. The on-screen About face shows the same owner avatar after the last tag. Why: the owner is metadata that helps a person judge whether to use the folio, as the tags do, so it reads as one of them, and the YAML matches the card, where the owner closes the tag row in the bottom-right corner and the tags are never empty. - Author, MVP (owner, 2026-09-29): the author is taken from the owner at the folio's first save to a Library. Owner and author differ where a folio is held by someone other than its drafter (a publisher's precedent, a firm library), so the author will show as its own avatar beside the owner; where the two are the same person, one avatar names both. A person picks their avatar from a selection and may change it at any time, initials until they do; the card shows the avatar alone, and hovering it names the person and their firm (owner, 2026-09-29). The author is stored as an account id and never edited; the name, firm and avatar shown are read live from that account, which the person edits in their Account details. Not yet built (GB-323).
Canonical top-level order:
identity:
guide:
tags: # ends with owner: <name>, read-only
libraries: # read-only, printed from Library entries
access:
logic: # post-MVP
content: # content_block — text, numbering, repeats, join_for (post-MVP)
data: # data_block — fieldsThe minimum authored card is identity.folio_kind and label, plus the
material wrapper on a block. handle prefills from the label and decouples
only when edited directly. owner is set by the act of creation. Every
absent member has a stated meaning: no guide is no standing instruction; no
access.hidden_for is visible to every authorised role; no
content.numbering is the app default scheme; no field required is not
required; no field value is unanswered. The objects a kind holds are
capabilities, not kinds: containers hold identity, access, tags, logic
and guide; a content block adds content with numbering, repeats and
join_for; a data block adds data. One keyed table drives the validator,
the About print and the nesting refusal, and no kind-switch exists outside it.
What the pillars cover
The owner's six pillars are a review lens for the schema, not a storage
structure. Each object on the card answers one of them: identity answers
what this folio is; position (the pin) answers where it sits;
access answers who owns it, may see it and may act on it; logic
(post-MVP) answers when it participates; numbering, repeats and
join_for answer how a block prints; guide and tags answer why —
what it is for and what helps a person or Goldie find and choose it. Three
things have no pillar and are deliberately outside the lens: substance (the
block's text or fields), provenance (derived_from, created_by) and
bindings (route, session, working revision). The lens changes no storage; it
is the checklist a reviewer walks to ask whether a proposed member has a home.
Gap — what Backlog tasks own
Stage E — proposals and Goldie address Folios. Proposals landed
2026-09-15 (GB-248): the proposals table and
convex/folio/proposalSchedule.ts address folio keys, filing records the
Document's working revision as baseline, and acceptance runs inside
runFolioTransaction with that revision as expectedRevision, refuses as
stale when it has moved, otherwise applies the whole schedule atomically and
advances the revision once, and rejection leaves no lineage trace
(Proposals Schema). Goldie herself — one agent per
folio, the Builder brief, the per-turn briefing and read tools — is GB-277
(One Goldie Per Folio); the scope
guard's remaining half and the insertion visual language are GB-145 and
GB-278.
Stage F — durable docs become wholly Current. Not started. The
Folios schema page still carries a Current / Target /
Gap split; the documents, modules and blocks schema pages describe deleted
tables; numbering, access, permissions, flow and DSL pages have doc-sync debt
(block-level numbering restart, the citation-grammar pointer, the field-type
pointer into the DSL spec); and roughly ninety source comments cite the
retired plans by path. A Backlog task owns rewriting or archiving those pages,
removing the plan citations once the docs own their rules, and passing
bun run docs:trace.
Related
- Folios Schema — the read and write contracts, the executor catalogue and the working revision.
- Folio About Is Schema-Bound YAML
- Folio Operations Resolve Once
- The Folio Tiers Share Parts, Not a Recipe
- The Stack — the compound shell the storage feeds without changing its anatomy.
Folio Operations Resolve Once
Why Folio action availability is resolved once in the domain, then projected to menus, agent instructions, and server enforcement
Frame Rulings, August 2026
Rulings settled in the owner's frame-review sittings of 2026-08-28 to 2026-09-04 that must not be re-raised — the grain of the unit, the ownership split over one envelope, the glyph menu as registry, the inherited-lock rules, and the build-order rulings