Skip to content
Back to skills

Scrivener

ASecurity

Scrivener project format internals, data model, and programmatic access. Use when parsing .scriv bundles, querying DuckDB exports, extracting manuscript text, or building AI-assisted novel tools from Scrivener data. Covers Windows-origin projects, cross-platform migration, and RTF content.

  • 61 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 29, 2026
documentationpythonsqldatabase

Works with

  • cli

Security analysis

A100/100

Scanned May 29, 2026

npx -y skills add plurigrid/asi --skill scrivener --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Scrivener?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Scrivener
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/plurigrid-scrivener/badge)](https://www.skillsdirectory.com/skills/plurigrid-scrivener)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: scrivener
version: 1.0.0
description: |
  Scrivener project format internals, data model, and programmatic access.
  Use when parsing .scriv bundles, querying DuckDB exports, extracting
  manuscript text, or building AI-assisted novel tools from Scrivener data.
  Covers Windows-origin projects, cross-platform migration, and RTF content.
---

# Scrivener: Project Format, Data Model & Programmatic Access

**Trit**: -1 (MINUS - validator/extractor)
**Color**: #E91A2F (Character Notes red)

## When to use this skill

- Parsing or inspecting `.scriv` project bundles (XML, RTF, metadata)
- Querying a DuckDB export of Scrivener data (documents, content, labels)
- Extracting manuscript text, character info, or synopses programmatically
- Migrating projects across Scrivener versions or platforms (Windows ↔ macOS)
- Building tools that read/write Scrivener project structures

## File Format: .scriv Bundle

A `.scriv` project is a directory. On macOS it displays as a single file (document package); on Windows it's a regular folder.

```
MyProject.scriv/
├── Files/
│   ├── Data/
│   │   ├── <UUID>/
│   │   │   ├── content.rtf       # Document body (RTF format)
│   │   │   ├── notes.rtf         # Inspector notes (RTF)
│   │   │   ├── synopsis.txt      # Synopsis text
│   │   │   └── snapshot-*.rtf    # Version snapshots
│   │   └── docs.checksum         # Integrity checksums
│   ├── binder.autosave           # Auto-saved binder state
│   ├── binder.backup             # Binder backup
│   ├── search.indexes            # Full-text search index
│   ├── styles.xml                # Document styles
│   ├── version.txt               # Format version
│   └── writing.history           # Session word counts
├── <ProjectName>.scrivx           # Master XML: binder tree + metadata
├── Settings/
│   ├── recents.txt               # Recent documents
│   ├── ui-common.xml             # Cross-platform UI state
│   └── ui.ini                    # Platform-specific UI state
└── QuickLook/
    └── Preview.html              # Finder preview (macOS only)
```

## Version History & Cross-Platform Migration

The ☼ project was **created on Windows** and has been migrated through multiple Scrivener versions:

| Version | Platform | Format | Notes |
|---------|----------|--------|-------|
| Scrivener 1 (Win) | Windows | XML `.scrivx` v1 + RTF | Original Windows port. `.scriv` is a visible folder. |
| Scrivener 1 (Mac) | macOS | Binary plist `.scrivproj` + RTF | macOS only, different format entirely. |
| Scrivener 2 (Mac) | macOS | Binary plist → XML | Transitional. No Windows v2 existed. |
| Scrivener 3 (Win) | Windows | XML `.scrivx` v2 + RTF | **Current**. Creator tag: `SCRWIN-3.x.x.x` |
| Scrivener 3 (Mac) | macOS | XML `.scrivx` v2 + RTF | **Current**. Creator tag: `SCRMAC-3.x.x` |

### Windows → macOS migration

- `.scriv` folder on Windows is a regular directory; on macOS it becomes a document package (UTI: `com.literatureandlatte.scrivener3.scriv`)
- Copy the entire `.scriv` folder to macOS and open with Scrivener 3 — it auto-upgrades
- The `Creator` attribute in `.scrivx` preserves origin: `SCRWIN-3.1.5.1` means Windows Scrivener 3.1.5.1
- `ui.ini` stores platform-specific UI state; `ui-common.xml` stores cross-platform state
- QuickLook/ only generated on macOS
- Line endings in RTF may differ (CRLF from Windows, LF on macOS) — both parse correctly

### Version upgrade path

Windows v1 → Windows v3: Scrivener auto-converts on open. Creates backup of v1 project first. Binder structure, labels, statuses, and content preserved. Custom metadata fields may need manual re-setup.

## .scrivx XML Schema

The `.scrivx` file is the master index:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<ScrivenerProject Template="No" Version="2.0"
    Identifier="UUID" Creator="SCRWIN-3.1.5.1"
    Device="HOSTNAME" Modified="2025-03-14 22:15:28 -0600"
    ModID="UUID">
  <Binder>
    <BinderItem UUID="..." Type="DraftFolder" Created="..." Modified="...">
      <Title>Draft</Title>
      <MetaData>
        <IncludeInCompile>Yes</IncludeInCompile>
      </MetaData>
      <Children>
        <BinderItem UUID="..." Type="Text" Created="..." Modified="...">
          <Title>Chapter 1</Title>
          <MetaData>
            <LabelID>2</LabelID>
            <StatusID>-1</StatusID>
            <IncludeInCompile>Yes</IncludeInCompile>
            <SectionType>-1</SectionType>
          </MetaData>
        </BinderItem>
      </Children>
    </BinderItem>
  </Binder>
  <LabelSettings>
    <Labels>
      <Label ID="0" Color="0.993 0.227 0.172">Red</Label>
    </Labels>
  </LabelSettings>
  <StatusSettings>
    <StatusItems>
      <Status ID="1">To Do</Status>
      <Status ID="2">In Progress</Status>
      <Status ID="3">First Draft</Status>
    </StatusItems>
  </StatusSettings>
  <ProjectProperties>
    <ProjectTitle>My Novel</ProjectTitle>
    <FullName>Author Name</FullName>
  </ProjectProperties>
</ScrivenerProject>
```

### BinderItem Types

| Type | Description |
|------|-------------|
| `DraftFolder` | Manuscript root (compile target) |
| `ResearchFolder` | Research materials container |
| `TrashFolder` | Deleted items |
| `Folder` | User-created folder |
| `Text` | Document (main content unit) |
| `PDF` | Imported PDF |
| `Image` | Imported image |
| `WebArchive` | Saved web page |

### Document Content Storage

Each document's UUID maps to `Files/Data/<UUID>/`:

- **content.rtf**: Body text. Contains inline annotations via `{\Scrv_fn=...}` custom tags.
- **notes.rtf**: Inspector notes pane.
- **synopsis.txt**: Plain text synopsis (corkboard cards).
- **snapshot-YYYY-MM-DD-HH-MM-SS.rtf**: Version snapshots.

### Color Values

Colors in `.scrivx` are space-separated RGB floats (0.0–1.0):

```python
# "0.952941 0.917647 0.329412" → #F3EB54
hex_color = f"#{int(r*255):02x}{int(g*255):02x}{int(b*255):02x}"
```

## DuckDB Export Schema

When exported to DuckDB (via `build_sun_org.py` or similar):

### `documents`
```sql
CREATE TABLE documents (
    project VARCHAR,          -- e.g. '☼'
    uuid VARCHAR PRIMARY KEY,
    title VARCHAR,
    parent_uuid VARCHAR,
    depth_int INT,            -- Nesting depth in binder
    item_type VARCHAR,        -- 'Text', 'Folder', etc.
    label_id INT,
    status_id INT,
    include_in_compile VARCHAR,
    binder_id VARCHAR,        -- Binder sort order
    section_type INT
);
```

### `content`
```sql
CREATE TABLE content (
    project VARCHAR,
    uuid VARCHAR,             -- FK to documents
    body TEXT,                -- Full RTF body
    synopsis TEXT,
    notes TEXT,
    body_length INT,
    content_file_type VARCHAR
);
```

### `labels`, `statuses`, `comments`
```sql
CREATE TABLE labels (project VARCHAR, label_id INT, name VARCHAR, color VARCHAR);
CREATE TABLE statuses (project VARCHAR, status_id INT, name VARCHAR);
CREATE TABLE comments (project VARCHAR, uuid VARCHAR, comment_text TEXT, position INT);
```

Additional tables: `collections`, `bookmarks`, `styles`, `section_types`, `projects`.

## Common Queries

### Manuscript text in binder order
```sql
SELECT d.uuid, d.title, c.body, c.synopsis
FROM documents d
JOIN content c ON d.uuid = c.uuid AND d.project = c.project
WHERE d.project = '☼'
  AND d.item_type = 'Text'
  AND d.include_in_compile = 'Yes'
  AND c.body IS NOT NULL
ORDER BY d.binder_id;
```

### Find documents mentioning a character
```sql
SELECT d.uuid, d.title, d.binder_id, length(c.body) AS bodylen
FROM documents d
JOIN content c ON d.uuid = c.uuid AND d.project = c.project
WHERE d.project = '☼' AND c.body ILIKE '%edith%'
ORDER BY d.binder_id;
```

### Strip Scrivener RTF tags
```python
import re
clean = re.sub(r'\{\\Scrv_fn=.*?\\end_Scrv_fn\}', '', body)
```

## RTF Content Notes

- **Inline annotations**: `{\Scrv_fn=footnote ...text... \end_Scrv_fn}`
- **Comments**: Stored in `comments` table with position offsets
- **Styles**: Referenced by name from `styles.xml`
- **Images**: Embedded as RTF `\pict` objects or referenced externally
- **Links**: Internal links use `scrivener://` protocol with UUID targets

## Character Data Extraction

Scrivener fiction templates include a Characters folder with sketch documents (Role, Occupation, Physical Description, etc.) — but these are **plain RTF**, not structured data. In the ☼ project, the Characters folder contains only a blank template.

Characters must be detected from prose:

```python
import duckdb

con = duckdb.connect('scrivener.duckdb', read_only=True)

def character_chunks(char_name: str) -> list:
    return con.execute("""
        SELECT d.title, left(c.body, 500) as preview, d.binder_id
        FROM documents d
        JOIN content c ON d.uuid = c.uuid AND d.project = c.project
        WHERE d.project = '☼'
          AND c.body ILIKE ?
          AND length(c.body) > 50
        ORDER BY d.binder_id
    """, [f'%{char_name}%']).fetchall()

# ☼ characters: she, narrator, ack, edith, deb, rad, glen, will, hub
```

## macOS vs Windows Differences

| Aspect | macOS | Windows |
|--------|-------|---------|
| `.scriv` appearance | Document package (single file) | Regular folder |
| Browse internals | Right-click → Show Package Contents | Open folder normally |
| UTI | `com.literatureandlatte.scrivener3.scriv` | N/A |
| QuickLook preview | Generated automatically | Not available |
| Spotlight indexing | Via `mdls` metadata | Windows Search indexes RTF |
| Line endings in RTF | LF | CRLF |
| Creator tag | `SCRMAC-3.x.x` | `SCRWIN-3.x.x.x` |

## Verify it worked

After parsing a `.scriv` project:

1. Check that the `.scrivx` XML parses and contains `<Binder>` with at least one `<BinderItem>`
2. Verify UUID directories exist under `Files/Data/` for documents listed in the binder
3. Confirm `content.rtf` files are valid RTF (start with `{\rtf1`)
4. If using DuckDB export: `SELECT count(*) FROM documents` should match binder item count

## What not to do

- Don't modify `.scriv` files while Scrivener has the project open — it uses file locks
- Don't assume synopsis or notes fields are populated — many projects leave them empty
- Don't parse RTF with regex for anything beyond stripping Scrivener tags — use a real RTF parser for styled content
- Don't assume macOS package structure on Windows — `.scriv` is just a folder there
- Don't delete `docs.checksum` — Scrivener uses it for integrity verification on open

## ☼ Project Specifics

- **949 documents**: 900 Text, 42 Folders, 2 PDF, 2 Image
- **432 manuscript chunks** with body > 50 chars
- **Labels**: Idea (#F3EB54), Chapter (#48B300), Scene (#468EFF), Notes (#E48738), Character Notes (#E91A2F)
- **Characters folder**: Only a blank template (unfilled)
- **No synopsis metadata** (1 boilerplate entry on Title Page)
- **2 inline comments**: Both authorial reminders
- **Origin**: Created on Windows Scrivener, migrated through version updates

## References

- [Literature & Latte](https://www.literatureandlatte.com/)
- [Scrivener 3 User Manual (macOS PDF)](https://www.literatureandlatte.com/docs/Scrivener_Manual-Mac.pdf)
- [File format analysis (Obsolete Thor)](https://preservation.tylerthorsted.com/2025/03/21/scrivener/)
- [Archive Team: Scrivener](http://justsolve.archiveteam.org/wiki/Scrivener)
- [Character management blog](https://www.literatureandlatte.com/blog/how-to-manage-your-characters-in-scrivener)

## GF(3) Triads

```
scrivener (-1) + catcolab-schemas (+1) + database-design (0) = 0
scrivener (-1) + build-sun-org (+1) + duckdb-ies (0) = 0
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…