ObjectStackObjectStack

Book

Book protocol schemas

Package Documentation Navigation — the book element (ADR-0046 §6).

A book is the spine of a table of contents: an ordered set of groups (sections) plus identity and access. It deliberately does NOT store its members. Membership — which doc sits in which group — is derived from a rule on each group (include glob/tag) plus an optional per-doc order/group, never held in a central array.

Why a spine and not a container (ADR-0046 §6.2.1): storing the whole tree in one array conflates low-cardinality group definitions (curated by a human, rarely changed) with high-cardinality membership (churned by the AI on every new doc). A central array forces a read-modify-write on every doc the AI adds — stale/concurrent edits silently drop or reorder siblings — and breaks overlay (RFC 7396 replaces arrays atomically, shadowing docs a later package version adds). A derived spine removes the write entirely: the AI creates a doc named to match a rule and it files itself (create-and-forget), and the only per-doc storage is the scalar doc.order, which merges cleanly.

Source: packages/spec/src/system/book.zod.ts

TypeScript Usage

import { BookSchema, BookAudienceSchema, BookGroupSchema, BookIncludeSchema, BookNodeSchema } from '@objectstack/spec/system';
import type { Book, BookAudience, BookGroup, BookInclude, BookNode } from '@objectstack/spec/system';

// Validate data
const result = BookSchema.parse(data);

Book

Properties

PropertyTypeRequiredDescription
namestringBook name (namespace prefix recommended, like every metadata name)
labelstringoptionalDisplay title
descriptionstringoptional
slugstringoptionalPortal URL segment; defaults to name sans prefix
iconstringoptional
ordernumberoptionalOrders books within the portal
audience'org' | 'public' | { permissionSet: string }optionalAccess audience; defaults to 'org' (inherits package grant)
groups{ key: string; label: string; order?: number; include?: string | object; … }[]The spine: ordered sections. Two levels total.
_lockEnum<'none' | 'no-overlay' | 'no-delete' | 'full'>optionalItem-level lock — controls overlay & delete (ADR-0010).
_lockReasonstringoptionalHuman-readable reason shown when a write is refused by _lock.
_lockSourceEnum<'artifact' | 'package' | 'env-forced'>optionalLayer that set _lock (artifact | package | env-forced).
_provenanceEnum<'package' | 'org' | 'env-forced'>optionalOrigin of the item (package | org | env-forced).
_packageIdstringoptionalOwning package machine id.
_packageVersionstringoptionalOwning package version.
_lockDocsUrlstringoptionalOptional documentation link surfaced next to _lockReason.

BookAudience

Union Options

This schema accepts one of the following structures:

Option 1

Type: 'org'


Option 2

Type: 'public'


Option 3

Properties

PropertyTypeRequiredDescription
permissionSetstring


BookGroup

Properties

PropertyTypeRequiredDescription
keystringStable group key (used by overrides, deep links, explicit doc.group)
labelstringSection title — first-class, i18n-homed
translationsneveroptional[REMOVED] Inline translations on a book (and on a book group) was removed in @objectstack/spec 17.0.0 (#4667, ADR-0049) — no resolver ever read it. The book tree endpoint and the docs portal render label / description verbatim in every locale, so a localized book shipped its authoring-locale strings to every reader. Delete the key. NOTE the near neighbour that DOES work: doc.translations is live and read on every doc render path — localize the docs themselves, and the portal picks the reader's locale up from there. Run os migrate meta --from 16 to rewrite existing sources automatically.
ordernumberoptionalOrder of THIS group within the book
includestring | { tag: string }optionalRule that derives membership (glob or tag)
packagestringoptionalScope the rule to a package id (default: the book package; cross-package via ADR-0048)
pages(string | { doc?: string; href?: string; label?: string; badge?: string; … })[]optionalOPTIONAL explicit override — hand-pin a curated order; wins over include

BookInclude

Union Options

This schema accepts one of the following structures:

Option 1

Glob over doc names, e.g. "crm_guide_*"

Type: string


Option 2

Match by doc tag (§5 vocabulary)

Properties

PropertyTypeRequiredDescription
tagstring


BookNode

Union Options

This schema accepts one of the following structures:

Option 1

Type: string


Option 2

Properties

PropertyTypeRequiredDescription
docstringoptionalDoc name to reference
hrefstringoptionalExternal link (use instead of doc)
labelstringoptionalOptional label override; title authority stays in the doc
badgestringoptionale.g. "beta" | "new"
iconstringoptional


On this page