Scrivener comments & footnotes
You help the writer work with Scrivener's two kinds of margin notes — comments and footnotes — each of which can be stored in two ways: linked (the note body lives in a side file and is anchored from the text) or inline (the note is written directly into the body text). Today the toolkit can detect that a document carries comments/footnotes; creating, editing, deleting, and converting them is on the roadmap because it needs the token-preserving RTF layer.
Always read the document first so you know which kinds of notes are present before proposing any change.
The two storage models
Scrivener stores a comment or footnote as either:
- Linked (margin) note — the note body lives in the per-document
content.commentsXML file (with author and color), and the anchor is an RTFHYPERLINKfield insidecontent.rtfwhose target isscrivcmt://<UUID>. The body and the anchor are two separate things in two separate files, joined by that UUID. - Inline note — there is no side file. An inline annotation (the comment-like
inline note) and an inline footnote are written directly into
content.rtfas marked ranges. Nothing incontent.comments.
A comment and a footnote differ only in role (margin remark vs. numbered note at
compile); both exist in linked and inline form. See
references/comments-and-footnotes.md for the
full storage map, the content.comments XML shape, and the planned commands.
Why this all lives partly inside content.rtf
Linked-note anchors (scrivcmt://), inline annotations, and inline footnotes are
encoded inside the RTF byte stream, alongside style markers, internal links, and
embedded images. That is the same reason scrivener-edit defaults to a
token-preserving edit model: naïvely regenerating "minimal RTF from text" would
orphan every linked comment (the anchor disappears but the content.comments body
stays, pointing nowhere), delete inline notes, and break links and images.
So writing comments/footnotes — placing or removing the HYPERLINK anchor,
editing the matching content.comments entry, or converting inline↔linked — requires
the token-preserving RTF writer. That layer is still being built, which is why the
write/convert commands below are marked planned, not available.
Detecting notes today (available)
read <id> exposes a constructs object. When a document contains any comment or
footnote, constructs.comments_or_footnotes is true:
python3 ${CLAUDE_PLUGIN_ROOT}/tools/scrivener/cli.py read "<uuid-or-title>" \
--project "<path.scriv>" --format json
Use this to answer "does this chapter have comments/footnotes?" and to decide whether
a later edit needs the destructive guard. The constructs flag tells you a note
exists; it does not yet return the note bodies, authors, or colors as structured
fields.
To pull the note bodies (linked comment/footnote text) out as Markdown or text, route
to scrivener-extract, which reads content.comments. Don't hand-parse RTF here.
Adding, editing, converting notes (planned)
These are the planned workflows. When asked, explain the intended command, note it is
not yet in the CLI, and suggest the closest available step (read to confirm what's
there; extract to pull bodies out; edit body text in scrivener-edit).
| Goal | Planned command |
|---|---|
| Add a linked or inline comment | comment add <id> --text … [--author …] [--color …] [--inline] |
| Edit / delete a comment | comment edit <id> <comment-id> … · comment delete <id> <comment-id> |
| Add a footnote (linked or inline) | footnote add <id> --text … [--inline|--linked] |
| Edit / delete a footnote | footnote edit … · footnote delete … |
| Add an inline annotation | annotation add <id> --text … · annotation delete … |
| Convert a note inline↔linked | note convert <id> --to inline|linked |
| List comments/footnotes (structured) | comment list <id> · footnote list <id> |
Until these ship, "convert inline footnotes to linked" cannot be done safely by the toolkit — say so plainly rather than risk a destructive RTF rewrite.
Safety (restate before any future write)
- Close the project in Scrivener and let cloud sync (Dropbox/iCloud) finish first.
- Writes auto-backup (zip) and auto-snapshot a document before overwriting its text.
docs.checksummismatches are advisory — never treat them as corruption.- Titles are not unique — address a document by UUID when a title is ambiguous.
- Never regenerate a rich document from plain text; a document with linked anchors,
inline notes, styles, links, tables, or images must be edited token-preserving (or
snapshotted and passed
--allow-destructivedeliberately).
Toolkit support
✅ Available now:
read <id>— exposesconstructs.comments_or_footnotes(true when the document has any comment or footnote); alsoconstructsflags for styles/images/tables/links/lists.
🔜 Planned:
comment add|edit|delete|list— linked & inline comments (author, color).footnote add|edit|delete|list— linked & inline footnotes.annotation add|delete— inline annotations in the RTF.note convert --to inline|linked— switch a note's storage model.
All planned commands depend on the token-preserving RTF write layer.
Related skills
- scrivener-extract — pull comment/footnote bodies out of
content.commentsinto Markdown/text (the way to see note text today). - scrivener-edit — token-preserving edits to the surrounding body text; explains why rich docs are never regenerated from plain text.
- scrivener-formatting — direct text formatting; comments/footnotes are notes, not
formatting, but both live inside
content.rtf. - scrivener-format — the package reference: where
content.commentsand thescrivcmt://anchors sit in a.scriv.