# Scrivener Formatting

> When the user wants to apply direct formatting to a Scrivener 3 project's editing text — fonts, size, bold/italic/underline/strikethrough, text or highlight color, alignment, line/paragraph spacing, indents, tab stops, lists, tables, or hyperlinks (Manual Ch.15 / the Format menu). Use when the user says "change the font for the whole project", "make this 12pt", "bold this", "italicize", "highlight this", "align center", or "convert to default formatting". This is the editing-font layer, NOT the compile output font. For named, reusable styles, see scrivener-styles. For the font of the exported/compiled manuscript, see scrivener-compile. For script-mode documents, see scrivener-scriptwriting.

- Skill: `donnfelker/scrivener-formatting` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add donnfelker/scrivener-formatting`
- Raw SKILL.md: https://api.skillmd.com/api/skills/donnfelker/scrivener-formatting/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: donnfelker (https://skillmd.com/u/donnfelker)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/donnfelker/scrivener-formatting

---


# Scrivener direct formatting (fonts and the Format menu)

You help the writer apply **direct formatting** to the text they edit in Scrivener —
the things on the **Format menu** (Manual Ch. 15): font family and size,
bold/italic/underline/strikethrough, text and highlight color, paragraph alignment,
line and paragraph spacing, indents and tab stops, lists, tables, and hyperlinks.
This formatting lives inline in each document's `content.rtf`, independent of named
styles.

Before doing anything, settle two questions: **which font are they actually asking
about** (editing vs compile), and **what scope** the change should cover (project /
subtree / specific docs). Get these wrong and you either edit the wrong layer or
rewrite far more than the writer intended.

## Editing font vs compile font — ask first

This is the most common confusion and you must resolve it explicitly:

- **Editing font (this skill).** The font, size, and formatting you see *while writing*
  in the editor. "Change the font for the whole project" almost always means this — make
  the on-screen text easier to read. It rewrites direct formatting inside each
  `content.rtf`.
- **Compile font (scrivener-compile).** The font of the **exported/printed manuscript**.
  Scrivener deliberately separates the two: a writer drafts in Courier and compiles to
  Times New Roman without touching their editing text. If the user wants "the manuscript
  in 12pt Times" or "the final PDF font", that is the **compile Format's** override, not
  this skill — hand off to **scrivener-compile**.
- **Override-formatting note.** Many compile Formats override editing formatting anyway,
  so changing the editing font may have **no effect on the output**. Say so when it
  matters, then confirm which layer the writer means.

When a request is ambiguous ("change the font everywhere"), ask: *"Do you mean the font
you write in, or the font of the exported manuscript?"*

## Direct formatting vs named styles

- **Direct formatting (this skill)** is applied straight to a text range — ad-hoc, not
  named, not reusable.
- **Named styles (scrivener-styles)** are reusable definitions (e.g. "Block Quote") that
  update everywhere when redefined. If the writer wants one consistent, re-editable look
  across the project, prefer a named style and point them to **scrivener-styles**.

Use direct formatting for one-off changes and for project-wide *normalization*
(e.g. "make all the body text 12pt Times"); use styles for semantic, reusable looks.

## Scope: project / subtree / selected docs

Every formatting change is **scoped**. Be explicit about which one applies:

| Scope | Means | Planned flag |
|---|---|---|
| **Selection / single doc** | One document (and, when supported, a range within it) | `--scope docs:<id>` |
| **Subtree** | A folder/container and all its descendants | `--scope subtree:<id>` |
| **Project** | Every text document in the binder | `--scope project` |

A "change the font for the whole project" request is **project scope** — a bulk rewrite
of every `content.rtf`. Confirm the scope and warn that it touches many documents.

## CRITICAL: project-wide rewrites must preserve RTF and skip script docs

Two hard rules for any bulk font/format rewrite:

1. **Token-preserving only.** Direct formatting lives inline in `content.rtf`, alongside
   linked comment/footnote anchors (`scrivcmt://` HYPERLINK fields), applied-style markers
   (`<$Scr_H::n>…`), embedded images (`\pict`/`pngblip`), and internal Scrivener Links.
   A bulk format change must edit the RTF token tree **in place**, never regenerate
   "minimal RTF from text" — naïve regex/regeneration silently orphans comments, drops
   style ranges, breaks links, and deletes images. This is the same token-preserving
   contract `set-text` uses (see scrivener-format / the RTF strategy).
2. **Warn about and exclude script-mode documents.** In script mode, screenplay elements
   (Scene Heading, Action, Character, Dialogue, …) are **recognized by their paragraph
   formatting** — indents, alignment, spacing. Bulk-reformatting a script document
   destroys that recognition and breaks the script. A project-wide format op must **detect
   script-mode docs, warn, and exclude them by default** (script formatting belongs to
   **scrivener-scriptwriting**). Never silently reformat a script doc.

## What you can do today

Direct formatting is a **🔜 planned** layer — the `format …` commands are not in the CLI
yet. What exists now lets you *inspect* formatting and *prepare* changes safely:

```bash
# See whether a document carries styles/links/images/lists/tables before any rewrite
python3 ${CLAUDE_PLUGIN_ROOT}/tools/scrivener/cli.py read <id> --project "<path.scriv>"

# The constructs flags (styles/comments/images/tables/links/lists) tell you what a
# bulk reformat would have to preserve — and hint where a doc may be script-formatted.
```

For brand-new text you author, `set-text` writes minimal valid RTF; for existing rich
documents it is token-preserving and refuses a destructive regenerate without
`--allow-destructive`. Use that as the model for how `format` will behave.

## Planned commands (roadmap — not yet in the CLI)

Describe the workflow, set scope, then note these are planned and suggest the closest
available step (inspect with `read`, hand off to `scrivener-styles` for reusable looks):

| Planned command | Does |
|---|---|
| `format set-font --scope …` | Set font family across the scope |
| `format set-size --scope …` | Set point size (e.g. "make this 12pt") |
| `format bold\|italic\|underline\|strike --scope …` | Toggle character formatting |
| `format color\|highlight --scope …` | Text color / highlight color |
| `format align --scope …` | Left / center / right / justified |
| `format spacing\|indent --scope …` | Line/paragraph spacing, indents, tab stops |
| `format list --scope …` | Bulleted / numbered lists |
| `format convert-default <id\|subtree\|project>` | Strip direct formatting back to the project's default editing format |

All take `--scope project | subtree:<id> | docs:<ids>` and the usual mutating flags
(`--dry-run`, `--no-backup`, `--no-snapshot`). Deeper construct detail
(fonts/`\fs`, color tables, alignment, spacing, lists, tables, hyperlinks) is in
**[references/formatting-model.md](references/formatting-model.md)**.

## Safety

Restate before any write (planned or otherwise):

- **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.
- **Titles are not unique** — use a **UUID** for any mutating command when a title is ambiguous.
- Never regenerate a rich document (comments/styles/images/tables/links) from plain text —
  edit token-preserving, or snapshot and pass `--allow-destructive`.
- A bulk format op **warns about and excludes script-mode documents** by default.

## Toolkit support

- ✅ `read <id>` — inspect a document's text + `constructs` flags (styles/comments/images/tables/links/lists) so you know what a reformat must preserve.
- ✅ `set-text <id>` — token-preserving text write; the model the planned `format` ops follow.
- 🔜 `format set-font` / `set-size` / `bold` / `italic` / `underline` / `strike` — character & font formatting.
- 🔜 `format color` / `highlight` / `align` / `spacing` / `indent` / `list` — color, alignment, paragraph & list formatting.
- 🔜 `format convert-default` — strip direct formatting back to the project default editing format.

All `format …` commands are roadmap (v0.1.0), not yet in the CLI. Be honest about this and
suggest inspecting with `read` or using a named style (scrivener-styles) in the meantime.

## Related skills

- **scrivener-styles** — named **Styles & Stylesheets**: reusable, re-editable looks. Prefer over direct formatting when the writer wants one consistent look project-wide.
- **scrivener-compile** — the **output/compile font** and Format overrides. This is where "the manuscript in 12pt Times" belongs.
- **scrivener-scriptwriting** — script mode. Bulk formatting must **not** break script docs; their elements are recognized by paragraph formatting.
- **scrivener-format** — the package/RTF reference hub: what lives inside `content.rtf` and why edits must be token-preserving.
- **scrivener-edit** — text writes (`set-text`) that share the token-preserving contract.

