> ## Documentation Index
> Fetch the complete documentation index at: https://opentrain.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Instruction Manuals

> How OpenTrain's agent-first instruction platform works: workspaces, manuals, canonical documents, changesets, publications, and audiences.

Instruction manuals are OpenTrain's rich documentation system for work projects: the guidelines, edge-case rulings, and reference material your workers follow. Agents author and maintain manuals through the API, CLI, and MCP with the same rigor as code — atomic changesets, immutable revisions, and reviewed publications — while humans edit the same documents in a collaborative editor.

## The hierarchy

* A **workspace** is the permission and asset boundary. Grants, private media, and changesets all live at workspace level.
* A **manual** is a reusable, multi-page document inside a workspace. Manuals bind to jobs, folders, or work projects with explicit precedence, so one manual can serve many surfaces.
* **Pages** form a bounded tree inside a manual (nested up to the manual's depth limit, default 5). Each page has a title, an audience, and a canonical rich-text body.

## Canonical documents

Every page body is a canonical `opentrain-tiptap/1` JSON envelope:

```json theme={null}
{
  "schemaVersion": "opentrain-tiptap/1",
  "doc": { "type": "doc", "content": [ { "type": "paragraph", "attrs": { "id": "…" }, "content": [ { "type": "text", "text": "…" } ] } ] },
  "checksum": "<sha-256 of the key-sorted doc JSON>"
}
```

Three properties make this agent-first:

* **Stable node IDs.** Every addressable block carries an immutable `attrs.id`. You patch, cite, and deep-link individual blocks without rewriting pages.
* **A closed vocabulary.** Only node and mark types the human editor can round-trip are valid. [`GET /instructions/capabilities`](/docs/developers/api-reference/instructions/capabilities) advertises the complete node/mark/attribute vocabulary, so you can author valid documents from first principles. Unknown node or mark types are rejected; unknown attributes surface as warnings.
* **Deterministic checksums.** The `checksum` is the SHA-256 of the recursively key-sorted `doc` JSON, so independently produced documents compare byte-equal.

## Changesets: page content and tree mutations

Page content and tree mutations — content patches, page creation, moves, renames, page archives, and asset attachments — travel as **changesets**: atomic batches of up to 250 operations against one workspace. Either every operation applies or none do. Workspace/manual metadata, permissions, asset preparation/finalization, and publication use their dedicated endpoints.

* Content edits use **stable-node patch operations** (`replace_node`, `insert_before`, `insert_after`, `append_children`, `set_attrs`, `delete_node`) guarded by the page's base revision and optional checksums.
* Whole-document replacement exists only as an explicit operation with `confirmReplace: true`.
* A `CREATE_PAGE` operation with a `clientPageKey` can be referenced by other operations in the same changeset as `parentPageId: "new:<clientPageKey>"` — build a whole nested section in one atomic write, in any operation order.
* Conflicts come back as structured objects (operation index, code, current revision/checksum), never prose-only errors.
* `Idempotency-Key` is supported by workspace/manual creation, direct changeset apply, changeset submit, stored changeset apply, revision restore, and publication. Replaying a key returns the original result; reusing a key with a *different* request is a `409`.

Validate and preview before writing: [`POST /changesets/validate`](/docs/developers/api-reference/instructions/validate-changeset) dry-runs the full plan and [`POST /changesets/diff`](/docs/developers/api-reference/instructions/diff-changeset) summarizes what would change.

## Direct writes and reviewed proposals

Two write modes share the same changeset format:

* **Direct apply** (`instructions:write`): [`POST /changesets/apply`](/docs/developers/api-reference/instructions/apply-changeset) writes immediately.
* **Submit for review** (`instructions:propose` + workspace `EDITOR`/`OWNER`): [`POST /changesets/submit`](/docs/developers/api-reference/instructions/submit-changeset) stores the proposal. A `REVIEWER` or `OWNER` with `instructions:review` [approves](/docs/developers/api-reference/instructions/approve-changeset) or [rejects](/docs/developers/api-reference/instructions/reject-changeset) it (optionally with a `decisionNote`), and an approved proposal is [applied by ID](/docs/developers/api-reference/instructions/apply-stored-changeset) through the same guarded write path. If pages drifted since submission, the apply records the proposal as `CONFLICTED` with structured conflicts instead of overwriting newer work.

## Revisions and publications

* Every applied changeset bumps the manual's **revision** — an immutable, numbered snapshot of every page. [Diff](/docs/developers/api-reference/instructions/diff-revisions) any two revisions; [restore](/docs/developers/api-reference/instructions/restore-revision) an old one as a *new* revision (history is never rewritten).
* Workers never read drafts. A **publication** ([`POST /manuals/{manualId}/publications`](/docs/developers/api-reference/instructions/publish)) freezes a manual revision into the worker-facing snapshot, filtered by audience. Publishing requires the `instructions:publish` scope and is reserved for workspace owners.

## Audiences and permissions

Pages and publications carry an audience tier — `ADMIN`, `CONTRIBUTOR`, `REVIEWER`, or `WORKER`. Published manifests use the monotonic ladder: a reader sees their tier and everything below it, so reviewer-only rubric notes never leak into the worker view. Working-tree `tree` and `search` audience filters are exact-match.

Workspace access is per-user: workspace creation persists the owner's `OWNER` permission record, and [permission grants](/docs/developers/api-reference/instructions/grant-permission) assign `EDITOR`, `REVIEWER`, or `VIEWER` to other users.

## Private media

Images, files, audio, and video are **private assets**, uploaded in two phases ([prepare](/docs/developers/api-reference/instructions/prepare-asset) → upload bytes → [finalize](/docs/developers/api-reference/instructions/finalize-asset)) and referenced from documents by asset ID only — raw storage URLs are rejected at write time. Finalization checks the prepared object and trusted upload metadata; the declared SHA-256 is not independently recomputed server-side. Reads mint short-lived signed URLs. Size limits per kind: images 25 MB, files 100 MB, audio 250 MB, video 2 GB.

## Renders and loss reports

The canonical JSON is the source of truth. HTML and Markdown are derived renders ([`POST /render-preview`](/docs/developers/api-reference/instructions/render-preview)); every Markdown render carries a machine-readable **loss report** listing exactly what the format could not express. Nothing is silently down-converted.

## Where to go next

* [Author instruction manuals](/docs/developers/guides/author-instruction-manuals) — the end-to-end guide.
* [API reference](/docs/developers/api-reference/instructions/capabilities) — every endpoint.
* [CLI](/docs/developers/cli/instructions) and [MCP](/docs/developers/mcp/instructions) — the same surface for terminals and agents.
