Asi scrivener
git clone https://github.com/plurigrid/asi
T=$(mktemp -d) && git clone --depth=1 https://github.com/plurigrid/asi "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/asi/skills/scrivener" ~/.claude/skills/plurigrid-asi-scrivener && rm -rf "$T"
plugins/asi/skills/scrivener/SKILL.mdScrivener: Project Format, Data Model & Programmatic Access
Trit: -1 (MINUS - validator/extractor) Color: #E91A2F (Character Notes red)
When to use this skill
- Parsing or inspecting
project bundles (XML, RTF, metadata).scriv - 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 v1 + RTF | Original Windows port. is a visible folder. |
| Scrivener 1 (Mac) | macOS | Binary plist + RTF | macOS only, different format entirely. |
| Scrivener 2 (Mac) | macOS | Binary plist → XML | Transitional. No Windows v2 existed. |
| Scrivener 3 (Win) | Windows | XML v2 + RTF | Current. Creator tag: |
| Scrivener 3 (Mac) | macOS | XML v2 + RTF | Current. Creator tag: |
Windows → macOS migration
folder on Windows is a regular directory; on macOS it becomes a document package (UTI:.scriv
)com.literatureandlatte.scrivener3.scriv- Copy the entire
folder to macOS and open with Scrivener 3 — it auto-upgrades.scriv - The
attribute inCreator
preserves origin:.scrivx
means Windows Scrivener 3.1.5.1SCRWIN-3.1.5.1
stores platform-specific UI state;ui.ini
stores cross-platform stateui-common.xml- 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 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 |
|---|---|
| Manuscript root (compile target) |
| Research materials container |
| Deleted items |
| User-created folder |
| Document (main content unit) |
| Imported PDF |
| Imported image |
| Saved web page |
Document Content Storage
Each document's UUID maps to
Files/Data/<UUID>/:
- content.rtf: Body text. Contains inline annotations via
custom tags.{\Scrv_fn=...} - 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):
# "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
documentsCREATE 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
contentCREATE 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
labelsstatusescommentsCREATE 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
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
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
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
table with position offsetscomments - Styles: Referenced by name from
styles.xml - Images: Embedded as RTF
objects or referenced externally\pict - Links: Internal links use
protocol with UUID targetsscrivener://
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:
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 |
|---|---|---|
appearance | Document package (single file) | Regular folder |
| Browse internals | Right-click → Show Package Contents | Open folder normally |
| UTI | | N/A |
| QuickLook preview | Generated automatically | Not available |
| Spotlight indexing | Via metadata | Windows Search indexes RTF |
| Line endings in RTF | LF | CRLF |
| Creator tag | | |
Verify it worked
After parsing a
.scriv project:
- Check that the
XML parses and contains.scrivx
with at least one<Binder><BinderItem> - Verify UUID directories exist under
for documents listed in the binderFiles/Data/ - Confirm
files are valid RTF (start withcontent.rtf
){\rtf1 - If using DuckDB export:
should match binder item countSELECT count(*) FROM documents
What not to do
- Don't modify
files while Scrivener has the project open — it uses file locks.scriv - 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 —
is just a folder there.scriv - Don't delete
— Scrivener uses it for integrity verification on opendocs.checksum
☼ 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
- Scrivener 3 User Manual (macOS PDF)
- File format analysis (Obsolete Thor)
- Archive Team: Scrivener
- Character management blog
GF(3) Triads
scrivener (-1) + catcolab-schemas (+1) + database-design (0) = 0 scrivener (-1) + build-sun-org (+1) + duckdb-ies (0) = 0