Documents

A rich-text document with version history, comments, workspace links and media — editable by a person in the app and by an agent through the same surface, at the same time.

8 min

Creating one

Choose the format at creation; you cannot rename it later.

beehaven call document-create '{"title":"Pricing","markdown":"# Pricing\n\nOne line."}'
beehaven doc add ./notes.md          # a local file, indexed for search
markdown and html are the explicit fields, and they are worth preferring because they state the format. content, body and text are also accepted and are treated as markdown.
An unrecognised key is stripped by validation, not rejected — so a misnamed field produces a confident success and no effect. Reach for explain before guessing a name; it reads the schema the server validates against, so it cannot go stale the way this page nearly did.

Every document gets a key (CLR-42) you can use as its address anywhere a document id is accepted, and its filename is that key plus its title.

Editing

Two verbs, and only one of them is safe by default.

document-editdocument-update
ChangesOne passage — find and replaceThe ENTIRE body
You supplyThe text to find, and its replacementEvery character you want to keep
If someone edited it meanwhileRefuses — the passage no longer matchesOverwrites their change
Use itAlmost alwaysOnly to replace a document wholesale
beehaven call document-edit '{
  "id": "CLR-42",
  "find": "pennies each",
  "replace": "a few cents each"
}'
find must match exactly once. Ambiguity is refused with a count rather than guessed, because an edit that lands on the first of three matches has changed something nobody looked at — and the document still reads plausibly afterwards. Pass all: true to opt in deliberately.

If the text is not found but its opening words are present, the refusal says so — that is the common cause, and it means the document changed since you read it.

Also
  • document-insertPlace a passage after / before a match, at a line, or at the top — exactly-once, like edit
  • document-appendAdd to the end. Also how you build a document larger than one write allows
  • document-outlineThe headings, with line numbers that feed straight back into get and insert
  • document-statsWords, characters, reading time, and what the document contains
  • document-renameThe title alone — no body argument, so it cannot destroy one

Working alongside a person

See what moved, then re-read only that.

beehaven call document-status '{}'         # what changed, and who changed it
beehaven call document-diff '{"id":"CLR-42"}'

An agent sees diffs of its own edits automatically — every mutating action returns one. What it could not see was yours, so it would answer from a body it read ten minutes ago with no way to know the document had moved underneath it.

document-status closes that. The useful field is not the timestamp but who: “four documents changed” is not actionable, “you changed three of these” says which one to re-read.

History

Every write is a restore point.

  • history-listThe restore points on a document
  • document-diffWhat changed between two of them
  • document-restorePut a previous version back, at the original id

A snapshot is taken before the write it protects, so a restore point holds the document as it stood beforehand. Writes close together are coalesced, so a typing session is one restore point rather than a hundred.

Comments

Anchored to the words, not to a position.

beehaven call document-comments '{"id":"CLR-42"}'

A comment stores the passage it refers to rather than a character range. A range into a document anyone can edit is wrong the moment a paragraph above it changes — silently, and now attached to different words. Storing the passage makes a stale anchor detectable: the read re-checks the body and reports which comments still find their text, and how many are orphaned.

A comment does not bump the document’s modified time. The gallery labels that column Modified, and a comment is not an edit.

Links between documents

A link stores an id, never a title.

beehaven call document-links '{"id":"CLR-42"}'

A workspace link holds the kind and the id of its target. A link that stores the title is a screenshot — rename the target and the document goes on saying the old name with nothing to notice. Links resolve by key first, because a key is what a person or an agent actually types.

document-links reports which targets are missing, which is what lets you answer “is this document still accurate” without opening every one.

Media, pages and export

Documents hold images, video, audio and YouTube embeds, and support explicit page breaks. Two view modes: the paged sheet, which shows where a page will break, and pageless, which drops the simulated sheet for reading on a screen. Pageless is a viewing preference stored per browser — it changes nothing about the document, so page breaks still break the page in print.

ExportHow
HTML · Markdown · Plain textFile → Download
PDFFile → Download as PDF (via Print → Save as PDF) — honours page setup and page breaks
Programmaticdocument-get, paged — 60k characters per call
There is no server-side PDF renderer and no DOCX export — the print route is the PDF route, and the menu says so rather than implying a renderer we do not have. DOCX and PDF import do work.

Size

A document can be much larger than a single write.

One write is capped at around 768KB; a document is not. Build a large one by creating it and then appending — a 2MB document is reachable that way and works end to end. The refusal on an oversized write names that route rather than only saying “too large”, which would read as documents cannot be this big.

Reads are capped too, on both lines and characters, and a truncated read reports which bound it hit and hands back a range to continue from.