# Write documentation for a package {#root}

@status:doc/work @audience:author

[p01] A manual for a package is itself a package: it names what it documents, carries a title and a summary, and is read rather than installed. This page writes one, with examples that are run and rules quoted from the source they come from.

[p02]
```prompt
Create a documentation package org.acme/notes-flow-docs in the current VibeVM project, as an in-tree package under vibevm/vibepacks/, documenting the package org.acme/notes-flow. Give it a manifest with kind doc, a title and an abstract, and a [[documents]] entry for the subject. Write one page explaining what the flow does, with a rule quoted from the subject's protocol by address. Run vibe doc check on it.
```

- needs: the vibevm skill installed for your agent; a project with `vibe.toml` at the root and the subject package in it

outcome: `vibevm/vibepacks/org.acme/notes-flow-docs/v0.1.0/vibe.toml` declares `kind = "doc"`, `title`, `abstract` and `[[documents]]`; the page under `vibevm/vibespecs/` has a first paragraph without terms and a `rule` block whose address resolves; `vibe doc check --citations` reports no unresolved citation

- assert: `grep -q "kind = \"doc\"" vibevm/vibepacks/org.acme/notes-flow-docs/v0.1.0/vibe.toml`
- assert: `vibe doc check --citations --path vibevm/vibepacks/org.acme/notes-flow-docs/v0.1.0`

## What happens {#what-happens}

[p03] The agent creates the package with the `doc` kind, fills the card, names the subject, and writes the first page in the XML dialect with the documentation vocabulary. `vibe doc check --citations` resolves every `rule` address against the subject's [specification](../glossary/index.xml#specification) and fails on any that does not exist. The manual is published like any package; the site finds it through the `[[documents]]` edge and, because the subject's group published it under the `-docs` name, shows it as the subject's [official documentation](../glossary/index.xml#official).

> [p04] **Default convention:** when the subject declares no `[documentation]`, the package `<name>-docs` in the same group counts as official and primary. A declared `[documentation]` replaces the convention entirely.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#REL-DEFAULT-CONVENTION>

## The manifest {#the-manifest}

[p05] A `doc` package must name at least one subject and carry a `title` and an `abstract`; it may declare a [skill](../glossary/index.xml#skill), images and, for a translation, the documentation it adapts. It may not declare a [boot snippet](../glossary/index.xml#boot-snippet), a binary or a server: documentation is read, never executed, and never enters a session's reading list.

> [p06] A `doc` package MUST declare at least one subject in `[[documents]]` (§4) and MUST carry `title` and `abstract` (§7).
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#KIND-DOC-MUST-DOCUMENT>

> [p07] A `doc` package MUST NOT declare `[boot_snippet]`, `[[mcp_server]]` or `[[binary]]`; `vibe check` rejects the manifest. Documentation never enters a boot lane (§14).
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#KIND-DOC-MUST-NOT-EXECUTE>

[p08] The `abstract` answers four questions in three to six sentences: what the manual covers, for whom, what it assumes known, what it leaves out. The `title` is the display name on every shelf; the [coordinate](../glossary/index.xml#coordinate) stays the identity, and the publisher is shown beside it. Images are optional source files in the package tree; when absent, the site draws a placeholder from the coordinate.

> [p09] `description` stays the one-line subtitle for lists and the page's meta description; `abstract` answers four questions — what it covers, for whom, what it assumes known, what it leaves out — and is bounded at about a thousand characters. The entry page does not restate the abstract; it inserts it through `derived kind="manifest-field"`.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#CARD-DESCRIPTION-AND-ABSTRACT>

> [p10] Placeholders are generated, never stored: a gradient or pattern for the banner and a glyph for the icon are computed from the hash of the coordinate, so a package looks the same on the site and in the local reader and different packages are distinguishable; the glyph depends on the kind — a book for `doc`, its own sign for every other kind; inline SVG at render time, no files, no network.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#CARD-PLACEHOLDERS-GENERATED>

[p11] A documentation package may also declare a skill, a `[translates]` table and `[media]`. Its pages live under `vibevm/vibespecs/` like the specs of any package, and only there is the documentation vocabulary open. The default name of a subject's documentation is the subject's name with `-docs`, in the same group.

> [p12] A `doc` package MAY declare `[[skill]]`, `[translates]` (§5) and `[media]` (§7).
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#KIND-DOC-MAY-DECLARE>

> [p13] Its pages live under `vibevm/vibespecs/` of its own tree like the specs of any package (PROP-052); a document belongs to the documentation genre by the kind of the package that contains it, and only there the documentation vocabulary of the dialect is open (PROP-045 `##DOC-VOCAB-BY-KIND`).
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#KIND-DOC-PAGES-LOCATION>

> [p14] The official-by-default documentation of a subject `<group>/<name>` is named `<group>/<name>-docs`, in the same group. The core documentation is `org.vibevm.core/vibevm-docs`, the companion of the host coordinate `org.vibevm.core/vibevm`.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#COMPANION-NAME>

[p15] Two more declarations are for the reader rather than the site. `authorship` in `[package]` says who wrote the prose, `human`, `ai` or `mixed`; it is a property of the document a shelf can filter by, never an attribution of the commits, whose law is the repository's own. `[navigation]` pins the pages a newcomer should see first and names the sections of the page tree; every other page keeps the order the package declares.

> [p16] A `doc` package MAY declare `authorship` in `[package]`: `human`, `ai` or `mixed` — who wrote the prose the package carries. It is metadata of the document, kept for the reader who filters a shelf by it; it is never an attribution of the commits or of the repository, whose authorship law is `spec://org.vibevm.core/vibevm/common/PROP-000#commits`. Absent means unknown: the site shows no badge and a filter by authorship leaves the package out of both named groups.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#CARD-AUTHORSHIP>

> [p17] A documentation package MAY declare `[navigation]`: `pinned`, the document paths the site and the local reader list first, in the order given; and `[[navigation.section]]`, one row per top-level folder of the page tree with the title the navigation shows for it. Pinning changes only where the named pages stand; every other page keeps the manifest's order. A pinned path that names no page is an error of `vibe check`.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#NAV-PINNED>

## The vocabulary of a page {#the-vocabulary}

[p18] Pages are written in the project's XML dialect, extended for documentation with a small vocabulary that ordinary specifications do not have. Each element is checked by a tool, which is the point of having it.

[p19]
| Element | What it does | What checks it |
| --- | --- | --- |
| `example` with `run` and `expect` | a command and its expected output, run in a fixture | the runner: exact match after declared normalisation |
| `rule ref="spec://…#ANCHOR"` | quotes a rule from a specification, live, in the specification's language | the [anchor](../glossary/index.xml#anchor) exists |
| `derived kind="cli-help | jtd-schema | manifest-field"` | inserts a generated reference block | regenerated at build; a divergence is red |
| `note kind="note | tip | warning"` | a call-out | the schema |
| `figure src alt` with `caption` | an image from the package tree | the file exists and passes the media rules |
| `prompt` with `needs`, `outcome`, `assert` | the request a user gives an agent to do the task, and the commands that prove it was done | an agent runs it in a clean fixture, then the asserts |
| `when="os:…"` on any block | a platform variant | the condition vocabulary |

> [p20] **The vocabulary is a parameter of the reader, not of the document.** `Vocabulary::{Spec, Doc}` (default `Spec`) selects the accepted element set through additive entry points (`from_xml_with`, `load_spec_text_with`, `project_spec_text_with`); the mapping «package kind → vocabulary» is the caller's, because the pivot knows no `PackageKind` by the separability law. A document declares nothing about its vocabulary.
>
> <spec://org.vibevm.core/vibevm/common/PROP-045#DOC-VOCAB-BY-KIND>

[p21] A page that quotes a normative value, a flag, a path, a field name, does so through `rule`; it never restates the value in prose, because a restated value is a second copy that drifts.

> [p22] **Documentation cites an anchor and never restates a normative value** — a number, a flag, a path, a field name. Where the prose must mention a value, the same sentence carries the source address.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#INV-DOC-CITES-NEVER-COPIES>

## The shape of a page {#the-shape}

[p23] A concept page has a noun as its title and opens with a paragraph that uses no term of the glossary. It shows an example before it explains, explains as a ladder where each step uses only the steps before it, and ends with edge cases and questions. A task page has an imperative title, opens the same way, and then gives the request for an agent before anything else: what to ask, what the agent needs, what you will see, and the commands that prove it worked. Manual steps follow only when they are worth walking. No page ends with a conclusion.

> [p24] **The page skeleton.** A concept page: a noun-phrase title; a first paragraph saying what this is and when it is needed with no glossary term at all (it is also the page's line in `llms.txt`; clarified 2026-09-12 at the first corpus check: a glossary word used in its ordinary English sense — package, project, kind, feature, workspace, translation — does not count, a word that means something only in vibe — lock file, manifest, registry, store, index, anchor, skill, contribution, fingerprint, receipt — does); an `example` with its `expect`; the mechanism as a ladder; edge cases through `rule`; questions only if real. A task page: an imperative title; the first paragraph without terms; then the `prompt` (§16 `##STYLE-PROMPT-FIRST`); «what happens» in three to six sentences as a corridor; «by hand» as numbered STE steps only where the manual road is worth walking; edge cases and questions. No page ends with a conclusion, a summary or a «next steps» box.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#STYLE-PAGE-SKELETON>

> [p25] **Prompt first.** Any action in VibeVM is done by an agent or by hand, and the agent is the main road. A scenario page opens with a `prompt` block: the plain request in the user's voice, self-contained (coordinates, paths and registry named, never implied), one prompt for one outcome, free of secrets, neutral to the agent (it works for any agent with the `vibevm` skill), at most sixty words; beside it `needs` (what the agent must have) and `outcome` (what the person sees when it worked), and at least one `assert` — a shell command that must exit zero after the agent's work, because a prompt cannot be checked by its output the way a shell example can. A prompt without an assert on a scenario page is a style-linter error; an illustrative prompt on an explanation page is marked `assert="none"`. `vibe doc check --prompts` runs every prompt through the configured agent runner (`[doc.prompts] runner`) in a clean temporary directory with the fixture and then runs the asserts; it is not part of the panel — it runs in the prose phase before acceptance, as a sample in the monthly loop, and in full at reconciliation. The skill `vibevm-docs` takes a page's `prompt` as the task when the user asks for what the page describes.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#STYLE-PROMPT-FIRST>

[p26] The full writing rules, including the banned words and the limits on sentence length in technical passages, ship with this manual as `AUTHORING.md`; `vibe doc check --style` enforces the mechanical part.

> [p27] **The mechanical check** `vibe doc check --style` gates a page: banned words and phrases by the page's language; sentence and paragraph length by block kind (errors in procedures and warnings, warnings in corridors); a glossary term used before its introduction; more than two glossary terms in one narrative sentence; deferral phrases («see the specification», «as described in») without an explanation on the same page; forbidden headings; exclamation marks, emoji, bold in prose; a readability score per page reported and not gated. A false positive is fixed in the linter's rule with a BACKLOG entry, never worked around in the text. A page is committed only after the author's self-edit against the norm and a green `--style`.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#STYLE-LINT>

## Checking and publishing {#checks}

[p28] `vibe doc check --examples --citations --derived --media --style` runs every check; the examples run against the real binary in a sandbox copied from the fixture the page names, and a page is committed only when the checks are green. Publishing is `vibe registry publish` like any package; a reader gets the manual with `vibe cache add`, and the site renders it when the [index](../glossary/index.xml#index-registry) announces it.

> [p29] **The example runner** (`vibe doc check --examples`) runs every `example` against the built binary and compares exactly after the declared normalisation; there are no match templates — every non-deterministic line is closed by a named `replace` rule visible in review. A page carries `run`, `expect` (stdout) and an optional `stderr`; the attribute `exit` defaults to `0`; an absent `stderr` asserts «stderr is empty». A fixture is a directory with a tree and an `example.toml` declaring the normalisation rules and the map «`--json` document → JTD schema» by the `command` field. The command's working directory is a fresh sandbox with a copy of the fixture, never the source tree; the command names no paths; isolation is one variable `VIBE_SETTINGS` in the native path spelling plus `NO_COLOR`; the behavioural variables (`VIBE_OFFLINE`, `VIBE_UNATTENDED`, `VIBE_INVOKED_BY`, `VIBETERM`, `VIBEFRAME`) are cleared and the flags stand in the example itself; a tripwire checks that the real `~/.vibe` and the source tree stayed unchanged; stdout and stderr are captured separately; examples document the non-TTY branch of the product and interactive prompts are described in prose; a `--json` stream is parsed document by document and each is validated by the fixture's schema map with a JTD validator written in `vibe-doc` (none exists in `vibe-wire`, whose schemas are codegen input); a document without a schema is reported as unchecked, never as passed. Normalisation: `<TMP>`, `<HOME>`, `<REPO>`, slashes, CRLF in expected files, `vibe <VERSION>` (package versions untouched), ANSI, block sorting by a declared line form, the fixture's local `replace` rules; the order is path replacements before slash unification and sorting after all replacements. Loosening a comparison to turn a check green is forbidden: the normalisation or the product is fixed.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#PIPE-EXAMPLE-RUNNER>

[p30] Every `rule` is a live citation without a pin: the page shows the [fact](../glossary/index.xml#fact)'s current text at every render, and the citation check asks one thing, whether the [anchor](../glossary/index.xml#anchor) still exists. Facts a specification marks as obligations for an audience must be cited by a page for that audience, and `vibe doc check --coverage` is that gate.

> [p31] Every `rule` yields a `documents` edge **without a pin**: the citation is live, and the page shows the fact's current text by address at every render. `vibe doc check --citations` checks one thing — that the anchor exists; a vanished anchor without a tombstone fails the build. There are no revisions, no text hashes and no «the spec moved ahead»: such checks would need a history the project does not keep by design.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#OBS-RULE-EDGE-UNPINNED>

> [p32] **The coverage gate.** Spec facts marked `actionstage="doc"` with an audience are *obligations*; `vibe doc check --coverage` requires every obligation to be cited by a page for the same audience — this is the ratchet PROP-047 `##DOC-COVERAGE-RATCHET` names, and `vibe progress report --view doc --audience …` is its listing of obligations, a source for the gate and not a navigation. Marking the obligations in the spec corpus is a campaign atom of its own. The site's navigation is derived from the page manifest, never from this report.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#OBS-COVERAGE-GATE>

## Edge cases and rules {#edge-cases}

[p33] Any group may document any package; the site shows such a manual on the community shelf with its publisher, and the subject's own group can promote it to official by naming it in `[documentation]`.

> [p34] **Official** documentation is the one whose edges converge: the subject named the package and the package declared the subject. **Community** documentation has only the edge from the documentation. An edge from the subject alone reads «not published or an error», and the site shows a warning.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#REL-OFFICIAL-IS-CONVERGENCE>

[p35] Examples in a README of an ordinary package are not run: the vocabulary opens only in packages of kind `doc`.

> [p36] Known limit: the README and specs of packages of other kinds cannot carry verifiable examples — the vocabulary opens by package kind. Their fences render at level 0 as they are, unverified.
>
> <spec://org.vibevm.core/vibevm/common/PROP-045#DOC-VOCAB-README-LIMIT>

[p37] A manual describes a version range of its subject through `[[documents]] version`, and the site shows, for each subject version, the newest manual whose range admits it.

> [p38] For a subject version V the site shows the documentation versions whose `[[documents]]` constraint admits V, choosing the newest.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#REL-VERSION-SELECTION>

[p39] A package with no documentation at all is still shown: the site renders any published version from its own bytes, the [manifest](../glossary/index.xml#manifest) as a reference page, the README, the boot snippet, the specs with their anchors, and the declared skills, binaries and servers.

> [p40] **Level 0.** The site renders any published version of any package from its own bytes: the manifest as a reference page, the README, the boot snippet marked «read by the session», the specs with anchors and fact highlighting by address, the declared skills, binaries and MCP servers, the dependants, «explained in», «translated into», and the images of `[media]`. Versions sit in the side navigation; `latest` is an alias.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#LEVEL-ZERO>

[p41] Such a rendering says so in its manifest, so a shelf marks it as generated, and the page of a bridge keeps the maintainer of the bridge apart from the author of what it wraps.

> [p42] The manifest of a level-zero rendering says so: `projection = true`, so a shelf can tell a page the site derived from a package's own bytes from a page an author wrote, and mark the first as generated. A bridge's rendering carries the two authorships the bridge keeps apart.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#LEVEL-ZERO-MARKED>

