Skip to main content
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:
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 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 dry-runs the full plan and POST /changesets/diff summarizes what would change.

Direct writes and reviewed proposals

Two write modes share the same changeset format:
  • Direct apply (instructions:write): POST /changesets/apply writes immediately.
  • Submit for review (instructions:propose + workspace EDITOR/OWNER): POST /changesets/submit stores the proposal. A REVIEWER or OWNER with instructions:review approves or rejects it (optionally with a decisionNote), and an approved proposal is applied by ID 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 any two revisions; restore an old one as a new revision (history is never rewritten).
  • Workers never read drafts. A publication (POST /manuals/{manualId}/publications) 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 assign EDITOR, REVIEWER, or VIEWER to other users.

Private media

Images, files, audio, and video are private assets, uploaded in two phases (prepare → upload bytes → finalize) 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); 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