Smaragd User Manual
Smaragd is a desktop writing tool for long-form fiction and other manuscripts organized as a folder of Markdown files.
It borrows ideas from Scrivener (binder, folder roles, templates), Longform/Obsidian (frontmatter metadata, wikilinks),
Lisa Cron’s Story Genius (structured story cards), and Helix (color themes, : command prompt).
This manual covers what the app does and how to use it. For internals (source layout, build/test commands), see the main README and ARCHITECTURE.md.
Installation
Prebuilt binaries for Linux, Windows, and macOS are on the Releases page. They’re built by CI, not signed with a paid code-signing certificate, so Windows and macOS both show a first-run warning — this is expected, not a sign of a broken or tampered download.
Windows
An unsigned .exe downloaded from a browser gets flagged by SmartScreen with a “Windows protected your PC” dialog. It’s a soft block:
- Click More info.
- Click Run anyway.
macOS
macOS tags anything downloaded via a browser with a quarantine attribute (com.apple.quarantine). Launching it then shows “cannot be opened because the developer cannot be verified” (or, on newer macOS, “is damaged and can’t be opened”). This is also a soft block, not a hard one:
-
Right-click the app → Open → Open Anyway — works on most versions, though Apple has tightened this on newer macOS: sometimes it takes a second step, going to System Settings → Privacy & Security and clicking Open Anyway there after the first failed attempt.
-
Or, more reliably, clear the quarantine attribute directly from Terminal:
xattr -cr /path/to/Smaragd.appThis strips the quarantine flag and sidesteps Gatekeeper’s warning entirely.
Linux
Four package formats are published on the Releases page:
-
AppImage — portable, no installation. Needs its executable bit set before it will run:
chmod +x smaragd-*-x86_64.AppImage -
.deb — for Debian/Ubuntu and derivatives:
sudo apt install ./smaragd-*-x86_64-linux.deb -
.rpm — for Fedora/openSUSE and derivatives:
sudo dnf install ./smaragd-*-x86_64-linux.rpm -
.flatpak — sandboxed, works on any distro with Flatpak set up:
flatpak install --user ./smaragd-*-x86_64.flatpak
Building from source
Building it yourself with cargo install or cargo run (see the README) only places the binary — none of the steps above that give the packaged builds their icon happen. What you get instead depends on the platform, because of a limitation in the windowing library Smaragd uses (winit), which only supports setting a window icon at runtime on Windows and X11 — it’s a no-op on Wayland and macOS:
| Platform | cargo install/cargo run | Packaged build (above) |
|---|---|---|
| Windows | icon shows (both the .exe file icon and the title bar) | same |
| Linux, X11 | icon shows in the title bar/taskbar; no entry in the application launcher | icon shows everywhere |
| Linux, Wayland (e.g. GNOME) | no custom icon anywhere | icon shows everywhere |
| macOS | no custom icon (the Dock icon needs a real .app bundle, which a bare binary doesn’t have) | icon shows in Dock/Finder |
If that matters to you, the simplest fix is to use one of the packaged builds above instead — they’re unaffected.
Projects
A project is just a folder on disk containing .md files and subfolders, marked with a .smaragd/project.json file. There’s no proprietary bundle format — you can open the folder in any other editor, sync it with any tool, and everything still works.
File > New Projectopens a template picker, then a native folder picker; it creates the folder, marks it as a project, and scaffolds in whatever the chosen template provides. If the folder you pick is already empty, the project is created directly in it — there’s no separate name prompt, since the folder’s own name already says what the project is called. Pick a non-empty folder instead (to hold the new project as a subfolder of it) and you’ll get the usual name prompt.File > Open Projectopens a native folder picker. If you point it at a folder smaragd hasn’t used before, it offers to adopt the folder in place (writing the.smaragdmarker) rather than refusing.File > Close Project(orCtrl+Shift+W) saves every open document (and any open Story Card draft) that has unsaved changes, then closes the project entirely — no save/discard/cancel prompt, same silent-autosave convention as Close Document. The Binder and every other dock tab return to their empty, no-project state, and a later “Reopen project on launch” won’t bring this project back, since closing it is a deliberate choice to leave it behind. Only enabled while a project is open.- With no project open, the Binder panel shows New Project / Open Project buttons in place of the empty binder — the first time you’ve ever opened a project in smaragd, New Project defaults to the World-Building template (see below) instead of Blank.
.smaragd/project.jsonstores things the filesystem can’t express on its own — manuscript ordering, folder roles, whether plugins/git are enabled for this project. If that file’s contents ever get corrupted, smaragd falls back to defaults rather than erroring; only a missing marker means “this isn’t a project yet.”
File > Settings has a “Reopen project on launch” option. With it on, Smaragd comes back exactly as you left it: the same document (or, with multi-tab editing on, every tab that was open) with the cursor where it was — including any unsaved edits a tab still had, restored rather than lost — the same binder selection and collapsed folders, Focus Mode if you were in it, and the window’s size and position (position isn’t restored on Wayland, which doesn’t let apps choose it). The dock layout and all settings are always kept between launches, whether this option is on or not. There’s also a separate “Ensure Research and Trash folders exist in every project” option (off by default) that creates those two role folders automatically whenever you open a project, recreating them at their original path if they were deleted since.
Project Templates
File > New Project shows a template picker before the usual folder picker (and name prompt, for a non-empty folder) — pick a starting scaffold, then locate the new project as before. Five templates ship built-in:
| Template | What it scaffolds |
|---|---|
| Blank (default*) | Nothing — an empty project, exactly like File > New Project behaved before templates existed |
| Novel | A Manuscript folder with two starter chapters, a Characters folder with a Protagonist document (Desire/Misbelief/Arc headings), plus Research and Trash folders (roles already assigned) |
| Nonfiction | A Manuscript folder with an Introduction and a “Part One” subfolder containing a first chapter, plus Research and Trash |
| Screenplay | A Screenplay folder with Act One/Two/Three starter documents, plus Research and Trash. Smaragd’s editor is plain Markdown, not Fountain — this reproduces a screenplay draft’s look with headings, not a real screenplay-format pipeline |
| World-Building | A Manuscript folder with a starter chapter, Research, a World folder (Characters with Main/Supporting subfolders, Locations, Items), and a Templates folder with Character/Location stationery documents (${{name}} placeholder, “New From Template” — see Template Variables), plus Trash — all roles already assigned |
* The very first time you’ve ever opened a project in smaragd, the picker instead starts on World-Building — see Projects.
File > Save Project as Template… turns your current project’s own folder/document structure into a reusable custom template, prompting for a name. It excludes:
- Whatever’s currently inside the project’s Trash folder (if one’s configured)
- Narrative state that belongs to one specific project, not a reusable shape: story cards, the protagonist Desire/Misbelief pair, and book/export/git metadata
Custom templates are stored in smaragd/project_templates/ in the platform config directory (the same base path as custom themes/styles/plugins — see Plugins):
- Linux:
~/.config/smaragd/project_templates - macOS:
~/Library/Application Support/smaragd/project_templates - Windows:
%APPDATA%\smaragd\config\project_templates
Each is a subfolder containing a template.toml (label, description) and a content/ folder mirroring the structure to stamp out. Unlike custom themes/styles, there’s no “Reload Custom Templates” button — a hand-dropped or hand-edited template only shows up in the picker after restarting the app (saving one via Save Project as Template… refreshes the list immediately, since the app already knows it just wrote it).
The Menu Bar
The top menu bar — File, Edit, View, Tools, Versions, Window, Help — can be driven entirely from the keyboard:
- Alt+letter mnemonics drop a menu down without touching the mouse:
Alt+FFile,Alt+EEdit,Alt+VView,Alt+TTools,Alt+SVersions (Versions usesSsince View already claimsV),Alt+WWindow,Alt+HHelp. - Arrow-key navigation once a menu is open:
Up/Downmoves the highlighted item within the open dropdown, wrapping at the ends;Left/Rightswitches to the adjacent top-level menu, also wrapping, and auto-focuses its first item. - Nested submenus — including View > Theme, Window > Layouts, and File > Export Manuscript… when more than one folder holds the Manuscript role — are keyboard-navigable too:
Right/Enteron a focused trigger opens the submenu and focuses its first item,Up/Downmove within it, andLeftbacks out to the parent menu without closing it.
Dockable Tool Windows
The Binder, Backlinks, Tags, Bookmarks, Notes, Document Metadata, Editor, Preview, Corkboard, Story Grid, Belief Timeline, Pomodoro, Word Count, Collaborate, Sync, Streak, Dashboard, and Version Activity views are all one shared dockable layout — similar to the Properties window in Visual Basic’s IDE — rather than a mix of fixed panels, modals, and mutually-exclusive view modes. You can:
- Drag a tab’s title onto empty space to pop it out into its own floating window
- Drag a floating window’s title back onto the dock area to re-dock it
- Drag one tab onto another to group them together, switching between them like browser tabs
- Drag a tab to an edge of another tab or the dock area to split the layout and place it side by side
- Resize the dock area, or a floating window, by dragging its edge
Binder and Editor are present from the moment a project is open; Backlinks, Tags, Bookmarks, Notes, Metadata, Preview, Corkboard, Story Grid, Belief Timeline, Pomodoro, Word Count, Collaborate, Sync, Streak, Dashboard, and Version Activity start closed. Any tab can be closed via its × button, and reopened again from View > Binder, View > Backlinks, View > Tags, View > Preview, View > Corkboard, View > Story Grid, View > Belief Timeline, View > Metadata, Collaborate > Collaboration Panel, Versions > Version Activity, or (for Pomodoro, Word Count, Streak, Dashboard, Bookmarks, Notes, and Sync) Tools > Pomodoro Timer/Tools > Word Count/Tools > Streak/Tools > Dashboard/Tools > Bookmarks/Tools > Notes/Tools > Sync Panel (most also have shortcuts — see Keyboard Shortcuts). Toggling Preview, Corkboard, Story Grid, or Belief Timeline just opens or closes that tab next to the Editor rather than switching to an exclusive “view mode” — any combination of tabs can be open and arranged at once.
The whole arrangement — which tabs are open, how they’re split or floated, and window position/size — persists across restarts. Window menu:
- Save Current Layout… — names and saves the current arrangement
- Layouts — lists saved layouts; pick one to switch to it
- Restore Default Layout — resets to the default layout: Binder on the left, Editor in the center (occupying the majority of the space), and Metadata/Backlinks stacked on the right
The Binder
The left-hand panel is the binder — a tree view of your project folder, one of the dockable tool windows described above. It’s .gitignore-aware, and documents are shown without their .md extension.
- Navigate by keyboard: click a row (or Tab to it) to give it focus, then:
Up/Downmoves between rowsLeft/Rightcollapses/expands a focused folderEnteropens the focused document
- Drag and drop a file or folder onto another folder to move it there. Drag it onto another document instead to reorder — dropping it just before that document, within the same folder — without changing which folder it’s in.
F6(the remappable “Toggle Binder/Editor Focus” shortcut) jumps keyboard focus back and forth between the binder and the editor/preview, without touching the mouse.- Right-click a row for a context menu:
- New File / New Folder / New From Template (folders only — see Templates) — each prompts for a name (
Enterto confirm) - Rename — also prompts for a name, and updates any
[[wikilinks]]elsewhere in the project that pointed at the old name - Delete — shows a native confirmation dialog; if a Trash folder is configured, it’s worded as a move to Trash rather than a permanent delete
- Restore (on a trashed item) — moves it back to its original folder, offering to recreate that folder if it’s gone since
- Folder Role / Dropdown Source / Empty Trash (folders only) — see Folder Roles and Dropdown Source Folders
- New File / New Folder / New From Template (folders only — see Templates) — each prompts for a name (
- A folder with a role assigned shows a leading icon instead of a text label: 🔍 Research, 🗑 Trash, 📋 Templates, 📖 Manuscript, 🌐 World
- Click the root row (the project itself, at the very top of the tree) to switch the Metadata dock over to project-wide fields — see Project Metadata. The row gets the same persistent highlight a selected document gets, and clicking it also toggles the whole tree open/closed, the same as clicking any other folder row does
- Click any other folder row to switch the Metadata dock to that folder’s own metadata instead — see Folder Metadata. The form’s heading reads “Folder Metadata” instead of the document’s title, so it’s always clear which kind of row you’re editing
Binder Background Coloring
Binder rows — documents and folders alike — can be background-colored to make status, POV, or progress toward a word count target visible at a glance without opening the Metadata dock for each one. Four modes are available, switchable via View > Color Binder By, File > Project Settings > Binder (see Project Settings), the remappable “Cycle Binder Color Mode” shortcut (default Ctrl+Shift+C, cycling through the modes below in order), or by clicking the mode indicator that appears in the status bar once a mode other than Off is active (clicking it cycles too):
- Off — no background coloring at all. The default, so a new project’s binder starts uncolored until you opt in.
- Status — colors each row by its own
statusvalue, using whatever color you’ve assigned that status (see below). - POV — colors each row by its own
povvalue the same way. - Word Count Progress — a red→yellow→green gradient toward
word_count_target: a document uses its own word count against its own target; a folder uses the combined word count of every document nested inside it (computed on a background thread alongside the Word Count panel’s own total, so it never blocks the UI) against the folder’s own target.
A row with nothing relevant to the active mode — no status/POV assigned, or no target set — simply shows no color; there’s no fallback to a different mode.
Status and POV colors themselves are assigned from the Metadata dock: next to the Status:/POV: row (on both the document and folder forms), a color swatch button appears as soon as that field isn’t blank — click it to open a color picker. Each status/POV value’s color is shared project-wide, so coloring “draft” or “Alice” once colors every row carrying that value, document or folder alike.
A file with uncommitted git changes (when git integration is on, both app-wide and for the project) also gets a trailing “•” marker after its name — a folder shows the same marker if anything nested inside it is dirty. This is independent of the coloring modes above: it’s a plain text suffix, not a color, so it shows alongside whichever Color Binder By mode is active rather than competing with it.
Document Stats
Settings > Appearance > Show document stats in binder (off by default) adds a right-aligned lines/words/chars readout to every document row — e.g. 53/418/2345 for a 53-line, 418-word, 2,345-character document. The open document’s numbers update live as you type; every other document’s come from its file on disk, re-read only when it actually changes. Toggle it without opening Settings via the remappable “Toggle Document Stats in Binder” shortcut (default Ctrl+Alt+D).
Writing and the Editor
The main panel is a plain-text Markdown editor, borderless and filling the whole Editor tab — clicking anywhere in it, including below the last line of a short document, places the cursor there. The open document’s title (its filename, without the .md extension) is shown as a heading above the text, so it’s always clear which document you’re looking at even if the Editor tab itself is just labeled “Editor”.
Ctrl+S(orCmd+Son macOS) saves explicitly. With multi-tab editing off (the default — see below), the document also saves automatically when it loses focus (e.g. you click into the binder or another panel).- By default, opening a document replaces whatever’s currently open (saving it first if it has unsaved changes) — there’s no multi-tab editing unless you turn it on; see Multi-tab editing below.
File > Open Document…(orCtrl+P) opens an fzf-style quick-switcher: type a few letters and it fuzzy-matches against every document’s path, best match first — a query doesn’t need to be a contiguous substring, so e.g. “ch1sc2” can match “Chapter 1/Scene 2”. UseUp/Downto change the highlighted result,Enteror a click to open it,Escapeto cancel.File > Close Document(orCtrl+W) saves the current document if it has unsaved changes, then closes it — there’s no save/discard/cancel prompt, matching the same silent-autosave behavior as opening a different document. With multi-tab editing on, this closes the active tab specifically (see below).- smaragd remembers every document you open, along with where your cursor was in each —
File > Go Back/Go Forward(orAlt+Left/Alt+Right) step through that history, browser-style, and jump straight back to the cursor position you left. Opening a document you’re already viewing doesn’t add a duplicate entry, and navigating to a new document after going back drops whatever was ahead of you, the same way a browser tab does. With multi-tab editing on, this history is per-tab rather than shared — see below. Ctrl+Shift+Oopens the Recent Files switcher — another fzf-style quick-switcher likeCtrl+P’s, but scoped to this session’s recent documents rather than the whole project. The first press shows documents you’ve edited this session, most-recently-edited first; pressingCtrl+Shift+Oagain while the popup is still open switches to documents you’ve opened this session instead (edited or not), and pressing it again switches back — so you can quickly reach either “what have I been writing” or “what have I been looking at” without retyping a query.Up/Down,Enter/click, andEscapework the same as Open Document above.- Exiting the app (
File > Exit,Ctrl+Q, or closing the window) is different: if the open document (or, with multi-tab editing on, any open tab) has unsaved changes, or a Story Card editor is open with an uncommitted draft (see Story Cards), a Save / Discard / Cancel prompt appears instead of closing immediately. Save writes every unsaved document (and the card draft, if any) before exiting; Discard drops all of it without writing anything; Cancel leaves the app open exactly as it was.
Multi-tab editing
Off by default (Settings > Editor > Allow multiple documents open at once, Ctrl+,; see Settings). With it on, several documents can stay open at once, each in its own tab across the top of the Editor pane — a dirty dot next to a tab’s filename marks unsaved changes, and a × closes it.
A few things work differently from the single-document default while this is on:
- Each tab keeps its own buffer fully resident in memory. Switching tabs is instant and never touches disk — a tab is only written out when you close it, press
Ctrl+Son it, or exit the app. - Opening a document (from the Binder, a wikilink, search, or any quick-switcher) focuses its tab if it’s already open, rather than opening a second one for the same file.
- Go Back/Go Forward belong to whichever tab is active, not the app as a whole: each tab remembers its own trail of documents opened from it. Since opening a document always focuses or creates a tab rather than changing an existing tab’s content, Forward often has nothing to go to right after a Back — switching tabs directly is the normal way to move between documents that are already open.
- Joining a Collaboration session opens the shared document in its own tab too, so you don’t need to close what you’re already working on first.
Turning the setting off collapses back down to one tab immediately, saving any other dirty tabs first.
Picking up external changes
smaragd periodically notices files added, removed, or edited outside the app — a sync tool like Dropbox or Syncthing, a git pull run from a terminal, or hand-editing a file in another program — and reacts automatically, without needing a manual “Reload” action or a restart:
- The Binder rescans, so files added or removed elsewhere show up (or disappear) on their own.
- If the open document changed on disk and you have no unsaved edits to it, it’s silently reloaded to match.
- If the open document changed on disk and you have unsaved edits, smaragd doesn’t guess: a prompt lets you choose Keep Mine (your edits stay; the on-disk change is otherwise ignored) or Reload from Disk (your unsaved edits are discarded in favor of the external version).
The ☰ menu
A ☰ button sits in the Editor tab’s top-right corner:
- Backlinks in document — toggles a resizable panel below the editor’s own content showing every document that links here (see Backlinks), independent of the separate Backlinks dock tab. Also bound to
Ctrl+B. - Source mode / Reading view — switches the Editor tab itself between the plain-text editor and a rendered markdown preview, without needing the separate Preview tab. Also bound to
Ctrl+E. Switching back to Source mode restores the cursor to where it was left. - Rename… / Move file to… / Delete file — the same actions as the Binder’s own context menu, for whichever document is currently open. Move file to… opens an in-app, fuzzy-searchable folder picker rather than an OS file dialog.
- Find & Replace… — opens Find and Replace scoped to the current file.
- Open in default app / Show in system explorer — hands the file to the OS’s default application, or reveals it in the platform’s file manager.
- Reveal file in navigation — expands every collapsed ancestor folder in the Binder and focuses the file’s row there.
The last six rows only appear while a document is open.
Pasting and dropping attachments
Pasting (Ctrl+V) or drag-and-dropping an image or other file onto the editor saves a copy into the project and inserts a reference at the cursor, an image becomes a ![[attachment.png]] embed, anything else a [attachment.pdf](<attachment.pdf>) link. A clipboard image with no filename (e.g. a browser screenshot copy) gets a generated one.
Where the file is saved is a per-project setting (File > Project Settings > Attachments): next to the document that receives it, or in a single configurable folder for the whole project. An optional size cap can reject oversized clipboard images instead of silently saving them.
Line numbers
A gutter down the left edge of the Editor can show each line’s number — off by default, turned on with Show line numbers under Settings > Editor (Ctrl+,; see Settings). Numbers count logical lines (real line breaks in the file), not wrapped visual rows, so a long paragraph that wraps across several rows only gets numbered once, at the row where it starts — the same convention word-wrap-aware code editors use. Two strips to the left of the numbers show per-line markers: a bookmarked line’s diamond (see Bookmarks) and, to its left, a noted line’s dot (see Notes).
Focus Mode
Tools > Focus Mode (or F9) is a distraction-free writing mode, similar to Scrivener’s Composition Mode: the window maximizes and all chrome — menu bar, binder, other dock tabs — disappears, leaving just the current document centered in the available width. The paragraph your cursor is in stays at full brightness while other paragraphs dim, a typewriter-style aid for keeping your eye on the sentence you’re actually writing.
Focus Mode needs an open document to enter — with nothing open there’s nothing to focus on. Press Escape or F9 again to exit and return to the normal layout.
Spell check can be switched on or off automatically for the length of Focus Mode. Set this with In Focus Mode under Settings > Spell Check (see Spell Check).
Markdown Preview
View > Preview (or the Toggle Preview shortcut) renders the current document the way it will actually look once exported — fonts, sizes, justification, page proportions, and drop cap all come from the currently selected typesetting style, the same one the Export dialog uses. The open document’s title sits at the left of the top bar, same as the Editor pane — the Preview tab itself is just labeled “Preview”, so this is what actually confirms which document you’re looking at. A Style picker at the right of that same bar lets you switch styles live and see the change immediately; picking a style there updates the project’s export style too, so Preview and the Export dialog always agree on what you’ll get switching one from the other.
Headings, quotes, code blocks, verse, lists, and tables still render with sensible on-screen formatting, but no longer in the old color-coded “dev preview” palette — book export is effectively monochrome ink on a page, so Preview reads that way too.
Images work two ways:
- Standard Markdown:
 - Obsidian-style embeds:
![[image.png]]
Relative image paths resolve against the open document’s own folder, and must stay inside the project (a path that tries to escape the project root — via .. or a symlink — is refused). Remote http(s):// images are never fetched.
Zooming
Hold Ctrl and scroll over the Preview pane to zoom the rendered text in and out — handy for proofreading at a larger size or fitting more of a page on screen. Ctrl + + and Ctrl + - do the same from the keyboard, and Ctrl + 0 resets back to 100%. This only scales what’s shown in Preview; it doesn’t change the typesetting style’s actual font sizes, so Export is unaffected, and your zoom level is remembered the next time you open the app.
Verse
A ```verse fenced block preserves its line breaks exactly as typed, unlike an ordinary paragraph (where a single newline collapses into a space):
```verse
Roses are red,
Violets are blue.
It renders — in Preview and every [Export](export.md) format — in its own font, size, and italic setting (a style's `[verse]` table, see [Typesetting Styles](export-typesetting-styles.md); an older custom style predating this falls back to a sensible default rather than failing to load), defaulting to upright, not italic, since a verse block is your own poem rather than a quotation, independent of body text or blockquotes. Text inside a verse block is literal: bold/italic/`[[wikilinks]]`/`#tags` aren't parsed, the same limitation an ordinary fenced code block already has — a verse block is meant for the poem's own words, not for markdown syntax nested inside it. Straight quotes and dashes still curl if [Typewriter Quotes](#typewriter-quotes) is on, since a poem is prose, not code.
Dialogue, by contrast, doesn't need any special syntax — write it as plain paragraphs, and turn on Typewriter Quotes for proper curly quotation marks; see [Typewriter Quotes](#typewriter-quotes) below.
## Typewriter Quotes
**`File > Settings > Editor`** has a **"Typewriter quotes in Preview and export"** checkbox, off by default. When it's on, straight typewriter punctuation is rewritten wherever markdown gets rendered *from* — the Preview pane here, and every [Export](export.md) format:
| Typed | Rendered |
|---|---|
| `"straight double quotes"` | "curly double quotes" |
| `'straight single quotes'` | 'curly single quotes' |
| `--` | — (em dash) |
| `...` | … (ellipsis) |
Your `.md` file on disk is never touched — the source text you type stays exactly as typed, straight quotes and all. Only the rendered *view* of it (Preview, or a compiled DOCX/EPUB/PDF) changes, so switching the setting off later shows your original punctuation again, nothing was lost. Quote direction (opening vs. closing) is inferred from context, the same simple heuristic most word processors use — it isn't guaranteed correct in every edge case (e.g. deeply nested quotes), but handles ordinary dialogue and contractions correctly.
Wikilinks
Type [[Topic]] or [[Topic|Alias]] to link to another document by its filename (no path needed — resolution is by name, project-wide).
- In the preview, wikilinks render as clickable links.
- Ctrl+Click a link — in the preview, or directly in the editor in Source mode — or place your cursor on one in the editor and press Ctrl+Enter (the remappable “Activate Wikilink” shortcut — see Keyboard Shortcuts) — to jump to it. If the target document doesn’t exist yet, this creates it, in the same folder as the note you linked from.
- While typing
[[in the editor, an autocomplete popup filters matching document titles as you type. Navigate it with arrow keys or Tab, and press Enter (or click) to accept. - Broken-link styling: a
[[wikilink]]whose target doesn’t match any document in the project renders in a distinct color (both in the editor and the preview) instead of the normal link color, so a typo or a not-yet-created note stands out at a glance. Clicking (or Ctrl+Enter-ing) it still offers to create the missing document, same as always. This color comes from the active color theme (broken_wikilink), so it changes along with the rest of the palette — a custom theme can set its own.
Backlinks
View > Backlinks (or Ctrl+Shift+B) opens a dockable tool window (see Dockable Tool Windows) listing every other document that [[links]] to whichever one is currently open — the reverse of a wikilink.
Each entry shows the linking document’s title and a short snippet of the surrounding text, so you can tell why it links here without opening it. Click a title to jump to that document. A document that links more than once gets one entry per occurrence, grouped under its title. A Refresh button re-scans on demand, for the rare case where a file changed outside the app (e.g. a git pull) while your current document stayed open — otherwise the list updates automatically whenever you switch documents.
If no document is open, or nothing links to the current one yet, the panel says so instead of showing an empty list.
The same list can also be shown inline, in a resizable panel below the editor’s own content, instead of (or alongside) this dock tab — toggle it from the Editor’s ☰ menu or Ctrl+B (see Writing and the Editor).
Document Metadata (Frontmatter)
Each document can carry a YAML frontmatter block (Longform/Scrivener-style manuscript metadata) at the very top of the file:
---
type: Chapter
status: draft
pov: Alex
word_count_target: 2500
tags: [action, chapter-3]
---
Open View > Metadata (or Ctrl+Shift+M) to edit these fields through a dockable form (see Dockable Tool Windows) instead of hand-editing YAML. Unlike a typical dialog, there’s no Save/Cancel step — edits apply as you type, the same way typing in the main editor does. Smaragd only ever reads/writes these five keys:
| Field | Meaning |
|---|---|
type | Free-form section type — “Chapter”, “Scene”, “Part”, or anything you want. Not tied to folder nesting. |
status | Free-form drafting status — “draft”, “revised”, “final”, or anything you want. |
pov | Point-of-view character, free text. |
word_count_target | A target word count for this document. |
tags | A list of free-form tags, edited as removable pill-style chips rather than typed YAML — click × on a chip to remove it, and type into the adjoining box to add one: a comma or Enter commits it, and an autocomplete list of every tag already used elsewhere in the project appears as you type (click a suggestion to accept it). Any #tag mentioned in the document’s body (not just this list) also shows up here as its own chip, without a × — it’s not stored in tags:, so there’s nothing for this form to remove; edit the body text to change it instead. See Tags for how these two kinds of tags combine project-wide and how to search by tag. |
Any other YAML key you’ve hand-added to the block (or that some other tool wrote) is left alone — Smaragd never round-trips the whole block through its own data model, so unrelated keys survive a save untouched — and shown read-only in an Other fields section below the form, so a custom key isn’t invisible just because there’s no dedicated row for it. The frontmatter block is stripped from the Markdown preview so it doesn’t render as a garbled paragraph.
Edits also flow the other way: hand-editing the frontmatter block directly (in the Editor, or from outside Smaragd) updates this form immediately, the same as editing through it.
The Metadata panel also shows a Word count — a live, read-only count of the open document’s body (frontmatter excluded), recomputed continuously from whatever’s currently in the editor, not just what was last saved.
The Status: and POV: rows each show a color-swatch button once that field isn’t blank — click it to assign that status/POV value a project-wide binder background color. See Binder Background Coloring for what these colors are used for and how to switch which one (if any) the Binder actually displays.
Dropdown Source Folders
By default, type/status/pov are free text — nothing stops “Scene” and “scene” and “seen” from all being typed for the same field across a project. To turn one of them into a closed dropdown instead, right-click any folder and check it under Dropdown Source for Type, Status, or POV. That folder’s direct child documents’ titles (not documents in a subfolder of it) become the dropdown’s options for that field; the Metadata panel’s Type:/Status:/POV: row switches from a text box to a dropdown automatically as soon as a field has at least one folder assigned and one document in it.
A few things worth knowing:
- Independent per field, and independent of Folder Role. Type, Status, and POV each have their own separate folder assignment — the same folder can drive more than one field, or each can point somewhere different. Checking a folder here doesn’t touch whatever Folder Role it already has (or lack of one), and doesn’t exclude it from Export — so an existing Research folder of character bios can double as the POV dropdown’s source without anything else about it changing.
- Never destroys an existing value. If a document’s
pov: Alicewas typed before you ever assigned a POV folder — or Alice’s document has since been renamed or removed from that folder — the field still shows “Alice” as-is; it just isn’t one of the clickable options until you pick something else from the dropdown. - “(none)” is always the first dropdown entry, for clearing the field.
- Not recursive: only documents placed directly inside the assigned folder count, the same limitation Templates has.
Folder Metadata
Folders can carry the same five metadata fields a document’s own frontmatter does — but since a folder has no file of its own to hold YAML, they’re stored in the project’s .smaragd/project.json instead, one entry per folder.
Click any folder row in the Binder (other than the project root, which opens Project Metadata instead) to switch the Metadata dock to that folder’s own fields, headed “Folder Metadata” so it’s always clear you’re editing a folder and not a document:
| Field | Meaning |
|---|---|
Type | Free-form section type, same as a document’s. |
Status | Free-form drafting status, same as a document’s. |
POV | Point-of-view character, free text. |
Word Count Target | A target word count for everything nested inside this folder. |
Tags | Free-form tags, edited the same removable pill-style chips a document’s are. |
See Document Metadata for the fuller description of what each field means and how the chip editor works — it’s the identical form, just without a live Word count readout, an Other fields section, or inline-#tag chips in Tags, since a folder has no file or body of its own for any of those three to read from.
What actually uses it
- Status and POV feed Binder Background Coloring the same way a document’s own
status/povdo — a folder’s row gets colored by whichever value it carries, once that coloring mode is active. The color-swatch button next toStatus:/POV:assigns the same project-wide color a document’s swatch would; coloring “draft” or “Alice” once colors every row carrying that value, document or folder alike. - Word Count Target feeds the Word Count Progress coloring mode specifically: a folder’s row is colored by the combined word count of every document nested inside it (computed off the UI thread, alongside the Word Count panel’s own total) against the folder’s own target.
- Type and Tags aren’t read anywhere else yet — they’re carried along purely for parity with the document form, in case you want the same fields available at a glance without opening every document inside. In particular, a folder’s
Tagsdon’t feed the Tags dock or#tagsearch; only a document’s own tags do.
Folder metadata is entirely independent of Folder Role (Research/Trash/Templates/Manuscript/World) — the same folder can have both, neither, or either on its own; setting one never touches the other.
Project Metadata
Alongside per-document frontmatter, a project itself carries a handful of project-wide fields — a Title/Subtitle/Author, a one-line Point, a Logline, a What if premise question, and a longer Synopsis — for the book as a whole rather than any one document.
Rather than opening yet another dock tab, these reuse the same Metadata dock Document Metadata already uses: click the root row at the very top of the Binder (the project itself) and the Metadata dock switches over to this form instead of a document’s frontmatter. Clicking any document row switches it back.
- Title and Author are the same fields the Export dialog’s Title/Author use — editing them here or there keeps both in sync.
- Subtitle feeds into export the same way — see Export for exactly where it shows up in each output format.
- Point, Logline, What if, and Synopsis are new fields with no other home yet; they don’t currently appear anywhere in an exported DOCX/EPUB/PDF.
Like Document Metadata, there’s no Save/Cancel step — edits apply as you type. Point is a single-line field, same as Title/Subtitle/Author; Logline/What if/Synopsis evenly split whatever vertical space is left in the tab below it. Synopsis (the field most likely to run long) keeps its scrollbar always visible, while Logline/What if only show theirs once there’s actually more text than fits.
Project metadata and Sync
When a project is synced, its project-wide fields — everything on this page, plus folder roles, binder order, story cards, bookmarks, colors and whether the project’s images and PDFs sync — follow you between your devices. A few settings deliberately stay on each device: whether git support is on, whether the project’s plugins are enabled, the session and daily word counts, and the Writing Streak switch and schedule.
Tags
Beyond the tags: list in Document Metadata, you can tag a document by writing #tag directly in its body — e.g. “Alice discovers the #mystery behind her mother’s disappearance.” A tag needs at least one letter (so #42, a footnote- or issue-style reference, is never mistaken for one), can include digits/_/-// after the first letter, and ends at the first character outside that set — / lets you nest tags, e.g. #projects/smaragd. A #tag written inside inline code or a fenced code block is left alone, the same as a [[wikilink]] would be.
- While typing
#in the editor, an autocomplete popup filters every tag already used anywhere in the project, the same way[[suggests document titles — see Wikilinks. Navigate it with arrow keys or Tab, and press Enter (or click) to accept. - In the preview, an inline
#tagrenders with a subtle background pill in the link color, distinguishing it from plain text, and is clickable — opening the Tags window pre-filtered to that tag, the same as clicking a tag heading in the window itself (below).
The Tags window
View > Tags (or Ctrl+Shift+T) opens a dockable tool window (see Dockable Tool Windows) showing the combined tags — frontmatter tags: plus every inline #tag mention — of whichever document is currently open. Each tag is listed with every other document in the project that also carries it; click a document’s title to jump to it. A tag with no other matching document yet is still shown, so you can confirm what’s actually on the open document. A Refresh button re-scans on demand, the same as Backlinks’ own.
Nested tags (#projects and #projects/smaragd) are grouped hierarchically: #projects shows as a collapsible section with #projects/smaragd (and any siblings) nested underneath, rather than every tag sitting in one flat list regardless of nesting.
Click a tag heading itself, or type into the panel’s own Search box, to switch from “tags on this document” to a project-wide list of every document carrying that tag, regardless of what’s currently open — a Clear button empties the search box and returns to the current document’s own tags. Tag matching is case-insensitive throughout (#Mystery and #mystery are the same tag), though whichever casing a given document actually used is what’s displayed.
The :tag <name> command prompt command opens the Tags window pre-filled with a project-wide search for <name>, without needing to open the window or type into its search box first — its argument tab-completes against every known tag, the same as a note title or theme id does for other commands.
Renaming a tag
Click Rename… next to any tag heading in the Tags window to rename it everywhere in the project in one step: every document’s frontmatter tags: entry and every inline #tag mention, matching case-insensitively against the old name, are rewritten to the new one. There’s no separate confirmation step or affected-document list — think of it the same way as renaming a document, which similarly updates every [[wikilink]] pointing at it without asking first.
Bookmarks
A bookmark marks a specific line in a document so you can jump straight back to it later — project-wide, not scoped to whichever file happens to be open.
Setting a bookmark
Two equivalent ways:
Ctrl+F2toggles a bookmark at the cursor’s current line.- Click a line’s icon slot in the Editor’s line-number gutter (Settings > Editor > Show line numbers must be on for this — the shortcut works either way). A bookmarked line shows a ◆ there; clicking it again removes the bookmark.
Only one bookmark per line — toggling on an already-bookmarked line removes it.
The Bookmarks dock
Tools > Bookmarks (or Ctrl+Alt+B) opens a dock listing every bookmark in the project, sorted by document then line. Each row is a clickable link (like a Backlinks or Tags row) — click it to open that document and jump straight to the line — plus a Delete button.
A bookmark follows its document through a rename, a drag-and-drop move, and a move to Trash — including the round trip back out via Restore — so the dock keeps linking to it throughout. It’s only actually removed once the document is truly gone: permanently deleted (no Trash configured), or via Empty Trash. If a bookmarked document somehow can’t be resolved anyway, its row shows (not found) instead of a link — still listed (and deletable) even though there’s nowhere left to jump to, the same tolerant-of-drift behavior a Story Card’s linked document has if that document goes away.
Navigating between bookmarks
Alt+Down/Alt+Up step to the next/previous bookmark, in the same document-then-line order the dock lists them, wrapping around at either end — deliberately paralleling Alt+Left/Alt+Right’s Go Back/Go Forward history navigation. A bookmark whose document can’t be found is skipped.
Notes
A note pins a short piece of free text to a specific position — line and column, not just the line — in a document, project-wide, not scoped to whichever file happens to be open. Unlike a bookmark, which only marks a line, a note carries its own text, and a single line can hold more than one.
Adding a note
Two equivalent ways:
Ctrl+Shift+Jopens a small prompt for a note at the cursor’s exact position. Type the text, thenCtrl+Enter(or the Save button) to save; Escape or Cancel discards it.- Click a line’s note icon slot — to the left of the bookmark diamond — in the Editor’s line-number gutter (Settings > Editor > Show line numbers must be on for this — the shortcut works either way). A noted line shows a ● there. Clicking it opens the same prompt, pre-filled, to edit or delete the first note on that line; clicking an unmarked line’s note icon starts a blank one at the start of the line.
Saving an empty note deletes it instead of leaving a blank one behind.
The Notes dock
Tools > Notes (or Ctrl+Shift+N) opens a dock listing every note in the project, sorted by document, then line, then column. Each row is a clickable link (like a Bookmarks row) showing line:column, followed by a short excerpt of the note’s text — click the link to open that document and jump straight to the note’s exact position — plus a Delete button.
A note follows its document through a rename, a drag-and-drop move, and a move to Trash — including the round trip back out via Restore — the same as a bookmark. It’s only actually removed once the document is truly gone: permanently deleted (no Trash configured), or via Empty Trash. If a noted document somehow can’t be resolved anyway, its row shows (not found) instead of a link — still listed (and deletable) even though there’s nowhere left to jump to.
Navigating between notes
Ctrl+Alt+Down/Ctrl+Alt+Up step to the next/previous note, in the same document-then-line-then-column order the dock lists them, wrapping around at either end — one modifier up from Alt+Down/Alt+Up’s bookmark stepping, since bookmarks already own the unmodified pair. A note whose document can’t be found is skipped.
Folder Roles: Research, Trash, Templates, Manuscript, World
Right-click a folder and choose Folder Role to designate it as one of five special folders. A folder with a role assigned shows a leading icon in the binder (🔍/🗑/📋/📖/🌐) instead of a text label. Research, Trash, Templates, and World are exclusive — at most one folder per role, project-wide — but Manuscript isn’t: several folders can hold it at once, e.g. one per book in a series.
- Trash: deleting a file or folder moves it here instead of removing it from disk. Right-click the Trash folder for Empty Trash (permanent, with confirmation), or right-click a trashed item for Restore.
- Templates: any document placed directly inside this folder (not in a subfolder of it) shows up in every other folder’s right-click “New From Template” submenu. Picking one creates a new document from a copy of it — frontmatter included, with template variables substituted — after prompting you for a name. The template itself is never modified.
- Research: currently just a marker with no behavior yet attached — reserved for future features like word-count rollups. Unlike Trash and Templates, Export does not skip a Research-role folder — right-clicking one to export it exports it like any other folder.
- Manuscript: designates a folder as your project’s primary manuscript content, mirroring Scrivener’s Draft folder.
File > Export Manuscript…compiles straight from it instead of you having to right-click and find the folder yourself: if no folder has the role yet, it falls back to exporting the whole project; if exactly one does, it exports that folder directly; if more than one does, it opens a submenu to pick which one. It’s also what the Word Count panel’s “Manuscript folders only” tracking scope sums. - World: like Research, currently just a marker with no behavior yet attached — for a project’s worldbuilding content (characters, locations, items). The World-Building project template tags its
Worldfolder with this role automatically.
Template Variables
A template document can use these placeholders, substituted when a new document is created from it (also used by Daily Notes):
| Placeholder | Substituted with |
|---|---|
${{name}} | The name you typed when creating the document (without the .md extension) |
${{date}} | Today’s date, formatted per the date format set in File > Settings |
${{date:FORMAT}} | Today’s date, formatted per FORMAT instead — a one-off override |
${{time}} | The current time, formatted per the time format set in File > Settings |
${{time:FORMAT}} | The current time, formatted per FORMAT instead |
${{previous_day}} / ${{next_day}} | Yesterday’s/tomorrow’s date (also take a :FORMAT override) |
${{cursor}} | Where the text cursor lands once the document is created/opened |
For example, a template starting with:
---
type: Scene
---
# ${{name}}
Started ${{date}} at ${{time}}.${{cursor}}
typed into the “New From Template” prompt as “Aria” would produce a document starting with # Aria and today’s date and time in place of ${{date}}/${{time}}, with the cursor left right after “Started … at …”.
The date and time formats are each a single format string, shared by every template — they’re strftime patterns, the same mini-language used by date, printf, and most other tools that format dates from a code (if you know Obsidian’s Periodic Notes plugin, this is the same idea as its moment.js format field, just a different token syntax). They default to %Y-%m-%d and %H:%M (e.g. 2026-07-28 and 14:05) when left blank, unless a placeholder’s own :FORMAT override says otherwise. File > Settings > Templates and File > Project Settings… > Daily Notes both show a live-previewed “Example formats” list of the ready-made formats below, right next to the fields that use them, in addition to this page.
Individual codes, for building your own format — the ones most likely to be useful:
| Code | Meaning | Example |
|---|---|---|
%Y | 4-digit year | 2026 |
%y | 2-digit year | 26 |
%m | Month, zero-padded | 07 |
%-m | Month, no padding | 7 |
%B | Month name | July |
%b | Month name, abbreviated | Jul |
%d | Day of month, zero-padded | 28 |
%-d | Day of month, no padding | 28 |
%A | Weekday name | Tuesday |
%a | Weekday name, abbreviated | Tue |
%j | Day of year (1–366) | 209 |
%V | ISO week number (1–53) | 31 |
%H | Hour, 24-hour, zero-padded | 14 |
%I | Hour, 12-hour, zero-padded | 02 |
%M | Minute, zero-padded | 05 |
%S | Second, zero-padded | 09 |
%p | AM/PM | PM |
%Z | Time zone name | CEST |
%% | A literal % | % |
A code with no leading - (e.g. %d, %m) is zero-padded to a fixed width; adding one (%-d, %-m) drops the padding — useful for a human-readable date like July 28, 2026 rather than July 08, 2026. Any character in the format that isn’t a % code (spaces, -, /, ,, letters) passes through literally, which is also how a Daily Notes folder format like Journal/%Y/%m produces a /-separated subfolder path rather than a single filename.
Some common complete formats:
| Format | Example output |
|---|---|
%Y-%m-%d | 2026-07-28 |
%d/%m/%Y | 28/07/2026 |
%m/%d/%Y | 07/28/2026 |
%d %B %Y | 28 July 2026 |
%B %-d, %Y | July 28, 2026 |
%A, %d %B %Y | Tuesday, 28 July 2026 |
%Y%m%d | 20260728 |
%Y/%m | 2026/07 — a Daily Notes folder nested by year then month |
%Y/%m/%d | 2026/07/28 — nested by year, month, and day |
%H:%M | 14:05 |
%H:%M:%S | 14:05:09 |
%I:%M %p | 02:05 PM |
A format that isn’t a valid strftime pattern falls back to %Y-%m-%d (or %H:%M for a time format) automatically, both in a created document and in every live preview of the format — a typo here never blocks document creation.
Daily Notes
Off by default — turn it on from File > Project Settings… > Daily Notes with the Enable Daily Notes checkbox. While off, both the shortcut and :daily do nothing but show a toast pointing at that checkbox.
Once enabled, F8 (or :daily in the Command Prompt) opens today’s note, creating it first if it doesn’t exist yet. Pressing it again later the same day reopens the same note without touching its content.
The rest of the same Daily Notes settings page:
-
Folder: where daily notes are created, relative to the project root. Left blank, they go in the project root itself. Unlike most other folder settings in smaragd, this one doesn’t need to already exist — it’s created automatically the first time a daily note is actually written there, the same way Obsidian’s own Daily Notes/Periodic Notes plugins work. It’s also a strftime pattern (same mini-language as Filename format below): a plain name like
Journalpasses through unchanged, but something likeJournal/%Y/%mnests notes a per-year, per-month subfolder at a time — the preview underneath shows what today resolves to. -
Filename format: a strftime pattern for the note’s filename (without
.md), e.g.%Y-%m-%dfor2026-07-28.md. Defaults to%Y-%m-%dwhen left blank.Both fields share an “Example date formats” list right in the dialog — expand it for a handful of ready-made patterns with a live preview. For the full set of individual codes (
%Afor the weekday name,%-dfor a day number with no leading zero, and so on), see Template Variables. -
Template: an optional document from the project’s Templates-role folder to seed the note’s content from, the same substitution as “New From Template” — see Template Variables.
${{previous_day}}/${{next_day}}render using this filename format, so a template like:# ${{date:%A, %B %d, %Y}} [[${{previous_day}}]] | [[${{next_day}}]] ${{cursor}}produces a heading in a friendlier format than the filename itself, wikilinks to yesterday’s and tomorrow’s notes (by their actual filenames), and leaves the cursor ready to start typing. If the configured template document is later deleted, daily notes just fall back to being created blank — it isn’t an error.
With no project open, both the shortcut and :daily do nothing but show a toast saying so (checked before the enabled toggle, since there’s no project settings to have enabled it on in the first place).
Import
File > Import brings an existing manuscript into the currently open project as binder documents/folders, landing under whichever folder is selected in the binder (or the project root if nothing is). Four formats are supported, each with a different picker (a single file for the first three, a whole folder for Scrivener) and a different level of fidelity, since the formats themselves differ in how much structure there is to recover:
- Word Document (.docx) — split into one document per “Heading 1”-styled paragraph (the standard Word convention for chapter titles), falling back to a single document if the file has none. Bold/italic/strikethrough survive; a table is flattened to one plain paragraph per cell rather than reconstructed as a markdown table.
- EPUB — one document per chapter, in the book’s own reading order (its spine, a well-defined boundary unlike DOCX’s heading heuristic), titled from each chapter’s own first heading. Bold/italic/strikethrough/code survive, along with headings, blockquotes, and lists.
- Scrivener Project — pick the
.scrivproject folder itself (it’s a directory, not a single file). Its Draft/manuscript folder maps onto smaragd’s own Manuscript role; Trash is skipped entirely rather than imported. Bold/italic survive. This is the newest and least-tested of the four importers — if something looks wrong after importing a real Scrivener project, that’s expected territory, not user error. - PDF — always a single document, plain text only: no formatting, no chapter splitting. A PDF has no semantic markup to recover in the general case (just glyphs positioned on a page), so this is inherently the lowest-fidelity option of the four — reach for it only when nothing better is available.
Export
Right-click any folder in the binder and choose Export… to compile it — and everything nested inside it, in the same top-to-bottom order shown in the binder — into a single DOCX, EPUB, print-ready PDF, or LaTeX source file. A nested folder whose role is Trash or Templates is skipped automatically, so deleted or template content never accidentally ends up in a compiled manuscript. If Typewriter Quotes is turned on, the exported file gets curly quotes/em dashes/ellipses too, same as the Preview pane.
File > Export Manuscript… is a shortcut to the same dialog for whichever folder(s) hold the Manuscript role — see there for how it behaves with zero, one, or several such folders.
The export dialog has:
- Title / Subtitle / Author — plain book metadata, remembered for next time (the same fields shown in Project Metadata — editing them in either place keeps both in sync). Subtitle is optional; leave it blank if your book doesn’t have one.
- Style — a dropdown of typesetting styles (see Typesetting Styles). Fonts, page size, running headers, and drop caps all come from whichever style is selected, not from anything typed into this dialog. The same dropdown appears in the Preview tab; switching it in either place updates the other.
- Export as DOCX… / Export as EPUB… / Export as Print PDF… / Export as LaTeX… — each opens a native “Save As” dialog (defaulting to a filename built from Title/Subtitle —
"Title - Subtitle.docx", falling back to whichever one is set, ormanuscript.docxif neither is), then compiles.
Title/Subtitle/Author show up differently per format:
- DOCX/PDF/LaTeX get a centered title page before the manuscript — Title, then Subtitle (if set), then Author.
- EPUB has no title-page concept (it’s reflowable text, not paginated), so Subtitle instead folds into the book’s title metadata as
"Title: Subtitle"— that’s what shows up as the book’s title in a reader/library view. - A custom style’s running header (see Typesetting Styles) can reference
{subtitle}alongside{title}/{author}/{chapter}.
All four formats read from the same style, so switching styles changes DOCX, EPUB, PDF, and LaTeX output alike.
LaTeX
Unlike the other three formats, LaTeX doesn’t produce a finished, ready-to-read file — Smaragd has no LaTeX engine built in (PDF export uses an embedded Typst engine instead; there’s no equivalent pure-Rust LaTeX implementation to embed the same way). Export as LaTeX… instead writes a .tex source file, plus an images/ folder next to it if the manuscript references any images, for you to compile yourself with XeLaTeX or LuaLaTeX — not plain pdflatex, which can’t handle the fontspec package the generated source relies on for font selection and Unicode text (curly quotes, em dashes, etc., if Typewriter Quotes is on).
A few things the LaTeX output handles differently from the other formats:
- Heading fonts/sizes from the chosen Typesetting Style aren’t applied — headings use LaTeX’s own standard, well-tested sizing for chapters/sections instead. Body text, blockquotes, code blocks, and verse do use the style’s chosen fonts and sizes.
- Wikilinks render as plain text, not clickable cross-references (same as PDF export — only EPUB resolves them to in-book links).
- A drop cap (if the style has one) uses the
lettrineLaTeX package, which needs to be available in your TeX distribution (it’s part of the commontexlive-latex-extra-type bundles, not something exotic).
Typesetting Styles
Twelve built-in styles ship with smaragd — the first eight follow US/Amazon-KDP trim conventions, the last four follow UK/European ones:
| id | Label | What it looks like |
|---|---|---|
manuscript | Manuscript | Plain submission format: US Letter, 1in margins, double-spaced, ragged-right (not justified), no running header or drop cap |
trade_paperback | Trade Paperback | 6×9in trim, justified body text, a running header (author’s name / current chapter), and a drop cap on each chapter’s first paragraph |
mass_market | Mass Market Paperback | 4.25×6.87in trim (the standard mass-market size), small 9pt justified type and tight margins to match, running header, drop cap |
digest | Digest | 5.5×8.5in trim — between Mass Market and Trade Paperback, common for novellas and shorter literary fiction — justified, running header, drop cap |
hardcover | Hardcover | 6.14×9.21in trim (KDP’s hardcover size), roomier margins and a larger drop cap for a more formal feel, sans-serif (Atkinson Hyperlegible) headings over a serif body, running header shows book title / current chapter |
academic | Academic | A4, 12pt, ragged-right (not justified — matches APA-style manuscript guidance), no running header or drop cap; for a thesis chapter or paper draft, not a book |
large_print | Large Print | 7×10in trim, 18pt Atkinson Hyperlegible (a sans-serif designed for low-vision readers) ragged-right body text, no drop cap or running header — accessibility features, not decoration |
chapbook | Chapbook | 5×8in trim, generous margins, ragged-right (justification would fight a poem’s own line breaks), no drop cap, running header shows author/title rather than a chapter |
uk_b_format | UK B-Format Paperback | 129×198mm — the standard UK trade paperback trim, distinct from (not a rescale of) the US 6×9in Trade Paperback — 10pt justified, running header, drop cap |
uk_a_format | UK A-Format Paperback | 110×178mm — the UK mass-market paperback trim, smaller and narrower than the US Mass Market Paperback — 9pt justified, running header, drop cap |
a5 | A5 Paperback | ISO 216 A5 (148×210mm exactly) — a common European trade/paperback trim, used as a book size in its own right rather than cut down from a larger sheet — 10pt justified, running header, drop cap |
manuscript_a4 | Manuscript (A4) | manuscript’s exact submission conventions (double-spaced, ragged-right, no header or drop cap) on ISO A4 instead of US Letter, for submitting outside North America |
Like color themes and plugins, custom styles are .toml files you author or drop into smaragd/styles/ inside smaragd’s config directory (no in-app style editor):
- Linux:
~/.config/smaragd/styles - macOS:
~/Library/Application Support/smaragd/styles - Windows:
%APPDATA%\smaragd\config\styles
A minimal custom style:
id = "novella"
label = "Novella"
[page]
width_mm = 139.7 # 5.5in
height_mm = 215.9 # 8.5in
margin_mm = 15.0
[body]
font = "Libertinus Serif"
size_pt = 11
line_height = 1.2
justify = true
[headings]
font = "Libertinus Serif"
sizes_pt = [22, 19, 16, 14, 13, 12]
[blockquote]
font = "Libertinus Serif"
size_pt = 11
italic = true
[code]
font = "DejaVu Sans Mono"
size_pt = 10
id and label are required, along with the [page]/[body]/[headings]/[blockquote]/[code] tables — id is what selects the style and is lowercased automatically. sizes_pt needs all six sizes (one per heading level, h1–h6). Three more tables are optional:
[verse]
font = "Libertinus Serif"
size_pt = 11
italic = false
[drop_cap]
scale = 3.0 # first letter renders at 3x body size
[running_header]
left = "{author}"
right = "{chapter}"
[verse] styles a ```verse fenced block (see Verse) — same shape as [blockquote]/[code], but unlike either, it’s optional: a style file predating verse support that omits it falls back to a built-in default rather than failing to load.
{title}/{subtitle}/{author} are substituted with whatever’s typed into the export dialog; {chapter} (supported as a whole side’s content, not mixed with other text) shows the current chapter on the print PDF and LaTeX exports specifically — DOCX and EPUB don’t have a per-page “current chapter” concept, so a {chapter} token is just left blank there.
Heading font/size (the [headings] table) isn’t used by the LaTeX exporter — it uses LaTeX’s own standard sizing for chapters/sections instead of trying to override it per style. Every other table ([body], [blockquote], [code], [verse], [drop_cap], [running_header]) applies to LaTeX output the same as the other three formats.
“Libertinus Serif”, “DejaVu Sans Mono”, and “Atkinson Hyperlegible” (the built-in styles’ fonts) aren’t arbitrary choices — they’re guaranteed available to the PDF renderer specifically, bundled with smaragd itself rather than depending on what’s installed on your system. A custom style naming some other font still works for DOCX/EPUB (which just reference a font by name, the same way any other document does — Word/an e-reader substitutes if it’s not installed), and for PDF too if that font happens to be installed locally; if not, the PDF falls back to some available font rather than failing the export. LaTeX export writes the font name into a \setmainfont/\fontspec call (needing XeLaTeX or LuaLaTeX to resolve it) — if your TeX distribution can’t find a font by that name, compiling the generated .tex file will fail rather than silently substitute, unlike DOCX/EPUB/PDF.
Using your own font file
Naming a font that isn’t one of those three works for DOCX/EPUB/PDF as above, but the Preview tab can’t render it — it only knows the fonts actually installed with smaragd, so it falls back to a generic face on-screen even though the exported file uses the real font.
To make Preview (and PDF, without needing the font separately installed as a system font) use your own font file too, add a font_file key alongside font in any of [body]/[headings]/[blockquote]/[code]/[verse]. LaTeX export doesn’t read font_file at all — it only ever writes the plain font name into a fontspec call, so a font that isn’t separately installed as a system font won’t be found when you compile the generated .tex file, even though it renders correctly in Preview/PDF.
[body]
font = "My Custom Font"
font_file = "MyCustomFont.ttf"
size_pt = 11
font_file accepts a .ttf or .otf file, either as an absolute path or (as above) relative to the style’s own .toml file — so you can keep a style and its font side by side in smaragd/styles/ and reference it by filename alone. font is still what DOCX/EPUB write into the document and what the file is registered under for Preview/PDF, so keep it a real, sensible font name — it’s what a reader without the font installed will see substituted. Reload Custom Styles picks up a new or edited font_file the same as any other style change; a file that doesn’t exist or isn’t a valid font is skipped with an error message (that one font slot falls back to a generic face) rather than blocking the rest of the style from loading.
A relative font_file resolves against wherever that particular .toml file lives, which in turn lives in the OS-specific styles folder from the list above (Linux ~/.config/smaragd/styles, macOS ~/Library/Application Support/smaragd/styles, Windows %APPDATA%\smaragd\config\styles) — so font_file = "MyFont.ttf" always means “next to this style file” on every platform, no path syntax to adjust. An absolute path, though, is tied to the OS it was written for (/home/you/Fonts/MyFont.ttf vs. C:\Fonts\MyFont.ttf) and isn’t portable if you copy the style file to a different machine running a different OS — a path that isn’t recognized as absolute on the machine it’s loaded on is silently treated as relative instead (almost certainly not the file you meant), rather than erroring. Keeping the font next to the style and using a relative path avoids this entirely, and is the recommended approach if you ever share or sync your smaragd/styles/ folder across machines. Filesystem case-sensitivity is a related wrinkle: Linux is case-sensitive, macOS and Windows normally aren’t, so a font_file whose case doesn’t exactly match the real filename can still work on macOS/Windows but fail to be found on Linux.
Use Reload Custom Styles in the export dialog to pick up a new or edited .toml file without restarting. A style file that fails to parse, or whose id collides with an already-loaded style (built-in or another custom one — whichever loaded first wins), is skipped with an error message rather than stopping other styles from loading.
The Print PDF Specifically
Unlike DOCX/EPUB (which place text on the page or in an XHTML flow), the PDF target is real typesetting: smaragd embeds the Typst compiler directly (no separate install, no network access) and generates a Typst document from your manuscript and the chosen style, then lets Typst do the actual page layout — the same category of tool as LaTeX or InDesign, not a “print to PDF” of a web page.
That gets you, for free or close to it: automatic widow/orphan avoidance (Typst’s default), a running header that tracks which chapter you’re actually on per page, and a true sunk drop cap — the enlarged first letter with the next couple of lines wrapped narrower beside it, not just an oversized inline glyph — computed with hand-rolled layout math rather than a network-fetched Typst package, which smaragd deliberately avoids. The wrapped lines are always ragged-right even in a justified style, and how many lines the cap spans is an approximation rather than derived from the font’s exact metrics, so it may run slightly loose or tight for an unusual custom style.
After a successful PDF export, the status bar reports an estimated spine width for the resulting page count — useful for sizing a paperback cover, but a rough estimate based on a standard white-paper thickness constant, not a print-broker-grade figure. Confirm against your printer’s own spine-width calculator (e.g. KDP’s) before sending a cover to print.
What Export Doesn’t Do (Yet)
- No per-block styling for special block types beyond verse (see Verse) — the markdown parser has no other such concept today, only headings/paragraphs/quotes/lists/tables/code/images. Dialogue is deliberately not one of these: it’s handled as plain paragraphs with typewriter-quote curling, not a distinct block type, so this isn’t an open gap.
- No footnotes, in any export format — the markdown parser has no footnote concept at all, so a numeric reference stays plain text everywhere rather than becoming a real footnote.
- EPUB output is one general-purpose file, not separately tuned per e-reader (Kindle/Apple Books/Kobo).
- Wikilinks resolve to a real in-book link in EPUB, when the target document is also part of the same export — otherwise (and always, in DOCX and LaTeX) they render as plain text.
- LaTeX export writes
.texsource (plus animages/folder) for you to compile yourself with XeLaTeX or LuaLaTeX — see Export — rather than a finished file like the other three formats. It also doesn’t map a style’s heading font/size (LaTeX’s own standard sizing is used instead) or a custom style’sfont_file(only the plain font name is written, so a font not separately installed as a system font won’t be found when compiling).
Story Cards (Corkboard)
View > Corkboard opens a wrapping grid of scene cards. A card isn’t just a Lisa Cron Story Genius-style cause-and-effect breakdown — it also tracks the psychological change a scene represents: a character’s belief going in, and what it becomes coming out.
At the top of the Corkboard, two project-wide fields capture what Cron calls the “Third Rail” — the protagonist’s driving force, not tied to any one scene:
- Desire — the external/internal want the protagonist is pursuing
- Misbelief — the flawed, usually childhood-formed belief standing in its way
Every scene card below is meant to test or advance this pair. Each card has a header, always visible, and three tabs underneath it for everything else.
The header:
- Scene # — a free-text label, independent of manuscript order
- Alpha Point — the scene’s core moment
- Subplots — optional, comma-separated tags
- POV Character — becomes a dropdown once you’ve designated a Dropdown Source folder for POV (see Dropdown Source Folders), otherwise free text
- Linked documents — comma-separated, with autocomplete as you type. A card can link to more than one manuscript document (spanning several scenes), and more than one card can link to the same document. Only documents under a Manuscript-role folder are suggested (see Folder Roles) — falling back to every non-Trash/Templates document if the project has no Manuscript folder designated yet. Picking a suggestion appends a comma automatically, so it’s clear you can keep typing to add another
The three tabs:
- Plot — Cause (the external event that occurs) and Effect (its external and internal consequence)
- Belief and Knowledge — Prior Belief (what the POV Character believes going into this card), New Belief (what they believe as a result of it), Value Shift (a short label for the value at stake, e.g. “Trust -> Distrust”), and Knowledge Gained (comma-separated facts the character learns)
- Third Rail — Why It Matters (the scene’s link back to the protagonist’s Desire/Misbelief — why these events matter to them personally), Realization (what the protagonist comes to understand), and And So? (what they do next, as a result of that realization)
Cards are independent of the binder tree: you can reorder them freely, create a card with no linked document yet (pure plotting, before you’ve drafted the scene), or link a card to a document that later gets renamed or deleted — the link just resolves to “not found” rather than breaking anything, the same way a dangling [[wikilink]] behaves.
Story Grid
View > Story Grid opens a second view of the same cards as a table — one row per card. An Order dropdown at the top picks what that row order means: Manuscript (the default) sorts by whatever order each card’s earliest linked document sits in the binder today, read-only, same as before; Manual instead shows — and lets you reorder — the same freeform order you set on the Corkboard, with ⬆/⬇ buttons in the # column moving a row exactly the way Corkboard’s own Up/Down buttons do (it’s the same underlying order, just editable from either view). The chosen mode is remembered per project, like the rest of the Story Grid’s ordering.
Each row shows a computed manuscript position (#), the card’s own Scene # label (unchanged, shown alongside rather than replaced), every one of its linked documents’ titles, POV, and a word count summed across all of them (read live from disk, the same way the Metadata and Word Count panels do), and every field from the card — Cause, Effect, Why It Matters, Realization, And So, Prior Belief, New Belief, Value Shift, and subplot tags. The POV column prefers the card’s own POV Character when it’s set, falling back to the linked document’s frontmatter POV otherwise.
The columns shown, and their order, are configurable via the panel’s own Columns menu — reorder or hide any of them to fit what you’re working on.
In Manuscript order, cards with no linked document, or where every link is stale, group into an Unplaced section — a toggle at the top of the panel puts that section above or below the placed rows. Unlike everything else on this page, that toggle is an app-wide preference, not a per-project one: it’s remembered across every project you open, the same way UI Scale or your theme choice is. It has no effect in Manual order, since every card shows in its own place in the freeform order rather than splitting out. Clicking a linked document’s title opens it in the Editor, same as Corkboard’s own 🔗 link; clicking a row’s Scene # opens the card editor.
Switching back to Manuscript always reproduces the same order, regardless of anything reordered while in Manual: two cards sharing a manuscript position, or two Unplaced cards with no position at all, fall back to a fixed tie-break rather than whatever order Manual reordering happened to leave them in.
The POV and Words columns are colored the same way the Binder colors its own rows: a colored dot next to the POV name whenever that POV has an assigned color, and the word count itself tinted along the same red→yellow→green gradient toward the (first resolved) document’s word count target. Unlike the Binder, this coloring isn’t mode-switched — it’s always on, independent of whatever Color Binder By mode is currently active.
The Story Grid never reorders the manuscript itself, in either order mode — its # column always shows a card’s computed manuscript position where one resolves, and its Up/Down buttons (in Manual order) only move the card within the freeform Corkboard order, not the documents themselves. To reorder scenes in the manuscript, reorder the documents in the Binder.
Belief Timeline
View > Belief Timeline (Ctrl+Shift+E) shows one character’s arc across the whole manuscript: pick a POV Character from the dropdown (populated from whatever names story cards have set in their own POV Character field — not the Metadata panel’s POV dropdown source, since a card can describe a belief shift before any scene exists for it) and see their cards, in manuscript order, chained as Prior Belief → New Belief. A repeated belief that just restates the previous card’s New Belief is skipped, so the chain reads as one continuous arc rather than restating itself. Cards with no resolvable linked document trail at the end. Clicking a card’s linked scene opens it in the Editor, same as Story Grid.
If no story card has a POV Character set yet, the panel just says so — set one from the Corkboard card editor’s header to start populating this view.
Find and Replace
Edit > Find and Replace searches plain text across a chosen scope:
- Current file
- Current directory
- All unsaved (modified) files
- The whole project
Supports replace-one and replace-all.
Search Everywhere
Tap Shift twice quickly to open Search Everywhere, an IntelliJ-style search box that finds four kinds of thing at once:
- Documents, by name, fuzzy-matched the same way as
File > Open Document…(Ctrl+P). - Text inside every document in the project, case-insensitive. Text search starts once you’ve typed at least 3 characters. It includes unsaved changes in the open document.
- Actions: every command that has a keyboard shortcut (Toggle Preview, New File, Commit, and so on), shown with its current shortcut, plus any
:commands registered by plugins. - Settings, by name or related words. For example, “curly quotes” finds Typewriter quotes in Preview and export.
You can also open it with File > Search Everywhere… or Ctrl+Shift+A.
The tabs along the top are All, Documents, Text, Actions, and Settings. All shows the best few results from each source under a heading. The other tabs show only their own results, with more of them. Tab and Shift+Tab switch tabs, Up and Down move the highlight, and Escape closes the box.
Press Enter, or click a result, to act on it:
| Result | What happens |
|---|---|
| Document | The document opens. |
| Text | The document opens with the cursor at the match. |
| Action | The action runs, as if you’d pressed its shortcut. |
| Setting | Settings opens on the page with that setting. |
A tap only counts when Shift is pressed and released on its own. Typing capital letters, Shift+click, and shortcuts such as Ctrl+Shift+… never open Search Everywhere. Double Shift is also ignored while another dialog is open. To turn the gesture off, clear Double Shift opens Search Everywhere under Settings > Shortcuts. Ctrl+Shift+A keeps working either way.
Two kinds of action aren’t listed, because they act on the editor’s cursor: Activate Wikilink and Toggle Bookmark. : commands that take an argument, such as :theme dracula, still belong in the command prompt.
The Command Prompt
Tools > Command Prompt opens a Vim/Helix-style : command line. Arguments tab-complete where it makes sense (note titles, theme ids, tag names, plugin command names).
| Command | Effect |
|---|---|
:w / :write | Save |
:q / :quit | Quit |
:wq / :x | Save and quit |
:o <title> / :open <title> | Open a document by title |
:new <title> | Create a new document |
:dmode <dark|light|system> | Set the dark/light/system appearance |
:theme <id> | Apply a color theme (see Themes) — no argument clears back to plain dark/light |
:find <text> | Open Find and Replace pre-filled with <text> |
:tag <name> | Open Tags pre-filtered to documents carrying <name> |
:spell | Turn spell check off, or back on in the project’s last language |
:daily | Open today’s daily note, creating it first if needed (see Daily Notes) |
:git enable | Turn on git support for this project |
:git commit [message] | Commit; prompts for a message if omitted |
:git push | Push |
:git pull | Pull |
:git backup [message] | Commit and push in one step |
Any : command a loaded plugin has registered also works here (see Plugins) — plugin commands can never override a built-in name.
Every :git command (and the git entry in this prompt’s own autocomplete) does nothing, with a status message pointing at Settings, whenever git integration is turned off app-wide.
Pomodoro Timer
Tools > Pomodoro Timer (or the remappable shortcut, Ctrl+Alt+T by default) opens a Pomodoro dock tab — the classic interval-timer technique for focused writing sessions, alternating fixed blocks of work and rest.
- Start / Pause / Skip / Reset control the current phase. Skip jumps to the next phase immediately, whatever’s left on the clock; Reset returns to a fresh Work phase (it keeps your completed-session count for the day, it just stops the clock and rewinds the current phase).
- When a phase’s time runs out, smaragd automatically switches to the next one — Work leads to a Short Break, except every nth Work session (configurable, default every 4th) leads to a Long Break instead — and pauses, rather than continuing to run unattended. Starting the next phase is always a deliberate action, not something that happens silently while you’re away from the keyboard.
- “Show a desktop notification when a phase completes” (Settings > Pomodoro, off by default) fires an OS-level desktop notification the moment a phase ends on its own — useful if the app isn’t in focus. It only fires on an automatic completion, never on a manual Skip, since you already know about that one. There’s still no audible chime.
The timer keeps running whether or not its dock tab is open or visible (it’s part of the app’s state, not something tied to a window being shown), and a compact countdown — ⏱ Work 12:34 — shows in the status bar at the bottom of the window any time a session has been started, so it’s visible at a glance without needing to switch tabs. It doesn’t appear during Focus Mode, which hides the whole status bar; the dock tab itself is unaffected and still works there.
Durations default to the traditional 25 minutes of work, a 5-minute short break, and a 15-minute long break every 4 sessions — all four are adjustable in Settings.
Word Count
Tools > Word Count (or the remappable shortcut, Ctrl+Alt+W by default) opens a Word Count dock tab, Scrivener-style: a Draft Target for the whole manuscript and a Session Target for today’s writing, each shown as a progress bar against the project’s current word count.
- Track — a per-project toggle for what counts toward the total: Manuscript folders only (any folder holding the Manuscript role, falling back to the whole project if none is assigned yet) or Everything except Trash (every document except Trash and Templates content). Trash and Templates are excluded either way — the toggle only changes whether tracking is scoped to your Manuscript folder(s) or opened up to the whole project.
- Draft Target — type a target word count to see a progress bar (current / target); leave it blank to hide the bar.
- Session Target — a separate, smaller target for today’s writing, measured against words written since the session’s baseline rather than the Draft Target’s running total. The baseline rolls forward automatically at the start of a new calendar day, or immediately if you click Reset Session.
- Characters typed this session — a plain informational count, no target: every character you insert or delete in a tracked document adds to it, so typing 100 characters and then deleting them all reads 200, not a net 0. It only counts keystrokes in documents inside the current Track scope, resets when a project is opened or you click Reset Session, and isn’t saved to disk — it doesn’t survive quitting and relaunching smaragd.
- Refresh — recomputes the current word count immediately. There’s also a dedicated remappable shortcut for this, Refresh Word Count (
F5by default), so you don’t need the panel open to force an update.
The total doesn’t recompute on every keystroke or every frame — recomputing means re-reading every tracked document from disk, so it only happens on a handful of triggers (opening a project, a git pull, a folder-role or Track-scope change, an actual save, or an explicit Refresh) and always runs on a background thread so it never freezes the UI. Creating, deleting, moving, or renaming a document doesn’t trigger a recompute on its own — click Refresh (or its shortcut) if the count looks stale after one of those.
A compact 340 : 12,345 / 50,000 words segment (characters typed this session, then current/target words) shows in the status bar, next to the Pomodoro countdown, any time a Draft Target is set — the Session Target is dock-tab-only, not mirrored in the status bar.
Writing Streak
Tools > Streak (or the remappable shortcut, Ctrl+Alt+S by default) opens a Streak dock tab that tracks whether you’re keeping up with a self-set weekly writing schedule. Everything about it — including whether it’s on at all — is configured per project, right inside the tab itself, not in the global Settings dialog: different projects can reasonably want different paces (or none at all).
The tab itself has two inner tabs, Streak and Configure, switchable freely at any time. Opening the tab picks a sensible starting one for you — Streak if the project already has tracking on, Configure if it doesn’t (e.g. a project you’ve never set this up for) — but that’s just the default; nothing snaps you back to it afterward.
- Configure: an enable checkbox (“Track a writing streak for this project”), a word target for each day of the week (0 for a day off), how a week counts as “met,” and how many consecutive missed weeks turn the light red (default 2). All shown regardless of the enable flag, so you can set everything up before switching it on.
- Streak: once enabled, shows Last completed week — a traffic-light badge (green/yellow/red, or gray until there’s a full week of history) judged only from fully completed Monday–Sunday weeks. It never reacts to today or the still-in-progress current week, so it can’t turn red on a Monday morning before you’ve had a chance to write anything — and Progress this week, a live, purely informational progress bar for the current week’s actual words vs. target that never changes the badge’s color above it. If the project doesn’t have tracking on yet, this tab instead shows a short message and a button that jumps to Configure.
- Two ways to judge whether a week was “met” (set in Configure): Cumulative weekly total (the week’s total words meets the sum of that week’s targets — a big Saturday can cover a missed Tuesday) or Every day individually (each day with a nonzero target must be met on its own).
- A compact traffic-light dot plus a live percentage (e.g.
● 45%) mirrors both readings in the status bar (once enabled for the open project); clicking either opens the Streak tab.
Streak counts the exact same words as the Word Count panel’s Track scope — by default, Manuscript folders only. Words written in a folder outside your Manuscript folder(s) (Research, a Characters note, a loose file at the project root, etc.) won’t count toward your streak at all, even though they’re saved to disk — easy to miss the first time you test it. Switch Track to Everything except Trash in the Word Count panel if you want every document to count toward the streak too.
Dashboard
Tools > Dashboard (or Ctrl+Alt+G by default) opens a Dashboard dock tab showing your writing statistics as they evolve over time, as both numbers and graphs — per project, like Writing Streak.
At the top, a summary: total sessions, total writing time, total words written across those sessions, and how many documents you’ve created in the project so far.
Below that, four bar charts covering the last 60 days:
- Word count — the project’s tracked total each day (the same history Writing Streak is judged against).
- Sessions — how many times you opened the project each day.
- Documents created and Documents modified — the latter read live from each file’s own last-modified time, so it also reflects changes made outside smaragd (an external editor, a
git pull), not just edits made through the app.
A session starts when you open the project and ends when you close it, switch to a different project, or the app quits — it’s how many times you sat down to work on this project, and for how long, not a daily reset like the Word Count panel’s Session Target.
Two more charts show when you tend to write, aggregated across every session on record: Activity by day of week and Activity by hour of day. A toggle switches both between Words (words written) and Time (minutes spent) as the measured quantity — a session spanning midnight counts entirely toward the day and hour it started in, not split across two.
Collaboration
The Collaborate menu (and its dockable Collaboration Panel, Ctrl+Shift+L) lets two people edit the same document together in real time, peer-to-peer — no server, no account, no third-party service ever holds the manuscript text. (To keep your own devices in step in the background, see Sync — a separate, experimental feature that does use a server, one you host, with everything encrypted before it leaves your device.)
Hosting a session
- Open the document you want to collaborate on.
Collaborate > Host Session(needs a document open; disabled otherwise).- Smaragd generates a one-time connection code and shows it in the Collaboration Panel. Copy it and send it to your collaborator through whatever channel you’d already trust with the document itself — chat, email, whatever.
- The panel shows “Waiting for a peer to join…” until they do.
Joining a session
Collaborate > Join Session…(or Join Session… in the panel itself) opens the shared document in its own tab — with multi-tab editing on, whatever else you had open stays open alongside it; with it off (the default), it replaces whatever was open, same as opening any other document.- Paste the code your collaborator sent you and confirm.
- Once paired, the host’s document appears in your editor and either side can type — edits from both sides merge automatically.
While connected
Both sides just type normally in the Editor tab; there’s no separate “collaboration mode” to the editing experience itself. Under the hood, each side’s edits are diffed against a shared baseline and merged with a CRDT (the same category of algorithm behind Google Docs/Yjs), so concurrent edits from both people — even to the same paragraph — converge to the same result on both sides without overwriting each other or needing a manual conflict resolution step. When a remote edit comes in, your local cursor position is adjusted to stay put relative to the surrounding text rather than jumping.
The panel shows Connected to peer <fingerprint> once pairing completes — a short id derived from the peer’s network identity, useful for confirming you’re connected to who you think you are, not a name either side chooses. End Session stops collaborating; the document itself is unaffected and stays open normally afterward.
What opening a different document does depends on which side you’re on, regardless of whether multi-tab editing is on. If you’re hosting, switching to another document keeps the session running — your collaborator’s view follows along to the new document automatically, with a status message (“Your collaborator switched documents”) to explain why their editor content just changed. If you’re the one who joined, opening one of your own documents has nowhere to put the shared one, so you’re asked to confirm first: decline and the shared document keeps showing with the session still live, confirm and the session ends before your document opens. Either side closing the tab the session is in still ends the session immediately; closing some other tab doesn’t.
Reconnecting after a dropped connection
Your collaborator’s connection dropping — network loss, a laptop going to sleep and waking back up, a phone switching networks — doesn’t end the session outright. The panel shows “Lost connection to your collaborator — trying to reconnect…”, and Smaragd keeps trying to get them back for about a minute before giving up. Nothing needs pasting again: reconnection reuses the exact same connection code, so once the network comes back, the two sides just pair up again on their own — no fresh Host Session/Join Session… needed. If the joiner’s whole app closed rather than just its network dropping, pasting the same code into a new Join Session… reaches the still-waiting host the same way. Anything typed on either side while disconnected isn’t lost — it’s queued and sent the moment the connection comes back.
If about a minute passes with no luck, the panel falls back to “Lost connection to your collaborator” and the session is over for good — start a fresh Host Session/Join Session… to resume, the same as before. You can also give up early with the panel’s Cancel button instead of waiting out the full window.
Privacy and security
- No server holds your text — in this feature. (Sync, described in its own chapter, is different: it stores your project on a server you host, encrypted so the server can’t read it.) Peers connect directly to each other via iroh (falling back to iroh’s relay infrastructure only to help establish that direct connection when needed, the same way most peer-to-peer / video-call tools do) — the manuscript itself is never uploaded anywhere or stored by a third party.
- End-to-end encrypted, on top of iroh’s own transport encryption: every edit exchanged between peers is additionally encrypted with a key derived from a secret that exists only inside the connection code itself, so even iroh’s own relay infrastructure can’t read the content it’s helping relay.
- The connection code is the credential. Whoever holds it can join the session — treat it like a password for as long as the session is open, and don’t post it somewhere public. Joining requires proving you hold the secret from the code before the other side ever reports you as connected, so a stranger who reaches the host’s network endpoint without the code can neither read the session nor block the real collaborator from pairing.
- Each session’s encryption keys are freshly derived per session and tied to that specific connection code — an old code from a past session can’t be reused to rejoin a new one.
Sync (experimental)
Sync is experimental. It’s new, and its data format and server protocol may still change in ways that require re-creating vaults. Keep backups on and don’t rely on it as the only copy of anything you care about.
Sync keeps a project identical across your own devices — your laptop and your desktop, say — in the background, even when only one of them is open at a time. It works through a small sync server that you host yourself, and everything is end-to-end encrypted: your text is encrypted on your device before it is uploaded, and the server only ever stores data it cannot read. This protects the copy on the server and the trip there; the files on your own devices are ordinary, unencrypted Markdown, exactly as before.
Sync is one of three ways Smaragd can move a project around, and they do different jobs:
| What it’s for | Needs a server? | Keeps history? | |
|---|---|---|---|
| Sync (this chapter) | The same project on your own devices, always up to date (optionally with its images and PDFs) | Yes — one you host | No (see Sync is not a backup) |
| Collaboration | Two people editing one document together, live | No — peer-to-peer | No |
| Git | Deliberate, named versions and sharing through a git host | A git remote, if you push | Yes |
| Backups | Restorable zipped snapshots on this machine | No | Yes |
What you need
- A sync server. It’s a single small program you run on a machine you control — a home server, a VPS, a Raspberry Pi — either as a Docker container or directly, for example as a systemd service. Setting one up is covered in the server’s own self-hosting guide; it takes a few minutes with Docker. If someone else runs one for you, you just need its address.
- A passphrase you choose. It encrypts your data, and you enter the same one on every device.
Setting it up
1. Turn it on and tell Smaragd where the server is
Open File > Settings > Sync and fill in:
- Enable sync — the master switch. Nothing syncs while it’s off.
- Host — the server’s name, like
sync.example.com(just the name: nohttps://, no path). - Port — leave at
0to use the default (443 with HTTPS, 8080 without), or enter the one your server uses. - Path — only if a reverse proxy serves the server under a sub-path such as
https://example.com/smaragd/; usually blank. - Use HTTPS (TLS) — on by default. Turn it off only for a server on a network you trust; plain HTTP sends your device’s access token unencrypted (your text stays encrypted either way).
- Passphrase — see Your passphrase below. Show reveals what you typed.
- Name (under This device) — how this device appears in the vault’s device list. Blank uses “Smaragd on your OS”.
Test Connection contacts the server and tells you whether it’s reachable, so you can catch a typo before going further. If something needed is missing, the page says what.
2. Start syncing a project
Open the project, then open the Sync tab with Tools > Sync Panel (Ctrl+Shift+Y). A project that isn’t syncing yet offers two choices:
- Create Vault… — for the first device. This makes a new, empty vault on the server for this project and starts syncing straight away. If the server only lets its administrator create vaults (the usual setup), Smaragd asks for the server’s admin token — the one whoever set the server up chose. It’s needed only for this step: Smaragd doesn’t store it, other devices join with a pairing ticket instead, and if the server’s admin token is changed later your existing vaults keep syncing.
- Join Vault… — for every other device, see below.
3. Add your other devices
On a device that’s already syncing, open the Sync panel and press Make Pairing Ticket. Copy the ticket it shows and get it to your other device — by chat, email, whatever suits. A ticket works once and expires after 10 minutes.
On the other device: install Smaragd, do step 1 (the same passphrase!), open a project folder (an empty one is fine, or a copy of the project), open the Sync panel, press Join Vault… and paste the ticket. The Sync panel then shows which server the ticket points to (and warns if it uses plain HTTP) — check it’s yours and press Join. Smaragd pairs the device and the project begins syncing. A ticket only ever comes from one of your own devices; joining uploads the open project to the ticket’s server, so don’t use one someone else sent you.
The Sync panel
The panel shows where things stand:
- Up to date — synced 2 min ago — everything is in step.
- Syncing… — a pass is running.
- Offline — the server can’t be reached. Your edits are saved locally and sync as soon as it’s reachable again; nothing is lost.
- A red message with Retry — sync stopped and needs you. Typically the passphrase doesn’t match (fix it in Settings and sync restarts by itself), or this device was removed from the vault.
Below the status:
- Sync Now runs a pass immediately. (Smaragd also syncs about every 10 seconds, and right after you save with
Ctrl+S.Tools > Sync Now, orCtrl+Alt+Y, does the same from anywhere.) - Make Pairing Ticket — see above.
- Devices lists every device in the vault and when it was last seen. Refresh updates the list; Revoke removes another device — it stops syncing immediately, along with any unused pairing tickets it made. Use this if a device is lost or retired. Revoking cuts the device off from the server, but it still knows your passphrase: if a lost or stolen device could get at the server’s data some other way, choose a new passphrase and move to a fresh vault (see Your passphrase). Each device also shows which device added it (“added by laptop”): if you revoke a lost device, check for devices it added that you don’t recognize, and revoke those too.
- Stop syncing this project (expand it) removes this device from the vault and stops syncing this project. Your files stay exactly as they are here, and your other devices keep their copies. If it was the vault’s last device, the server deletes the vault’s encrypted copy after a while (30 days by default, set by whoever runs the server); your own files are never affected.
What syncs
- Your documents — every
.mdfile — and your folders, including empty ones. Edits, new files, renames, moves and deletions all follow you between devices. - Project settings — the binder order, folder roles, story cards, bookmarks, colors, word-count targets, the book title and the project’s title/logline/synopsis — everything in Project Metadata and its neighbours except the per-device parts described next.
- Images, PDFs and other files — only if you switch it on (see below).
What stays on each device: whether git support is switched on and its auto-commit settings, whether this project’s plugins are enabled, the running session word count and daily history, and the Writing Streak switch and schedule. Those are yours alone on each device. In particular, turning on plugins is never synced — a plugin runs code, so you decide device by device.
What doesn’t sync at all: your plugin scripts, your backups, and hidden or git-ignored files — and, unless you switch it on, anything that isn’t a Markdown document.
Images, PDFs and other files
By default only your Markdown documents sync. To also sync everything else in the project folder — cover images, reference PDFs, maps, research scans — tick Also sync images, PDFs and other files in File > Project Settings > Sync (see Project Settings). It’s a project setting, so it switches on (or off) on every device syncing that project.
- Files are synced whole, encrypted like everything else, in pieces so that large ones work. A file is only uploaded again when its content changes; renaming or moving it doesn’t re-upload it.
- There’s a size limit per file, set by whoever runs the server — 100 MB unless they changed it. A bigger file stays on this device and the Sync panel says so.
- Unlike text, a file can’t be merged. If two devices change the same file before they sync, one version wins on every device and the other is kept next to it as
name (conflict copy).ext, so nothing is lost. A file deleted on one device and changed on another comes back with the change, just like a document. - A new version replaces the old one on the server, so the vault only holds each file once — but while a new version is uploading it briefly needs room for both. Large files can use up a vault’s storage quickly; ask whoever runs the server if you hit its limit.
- Switching it off later stops syncing those files; nothing is deleted anywhere.
How edits from two devices are merged
Sync doesn’t ask you to pick “mine” or “theirs”. Each document is merged automatically, the same way live collaboration works, so you can edit on your laptop on the train and on your desktop at home and the results combine:
- Two edits to the same file — even in the same paragraph — are both kept.
- A rename and an edit to the same file both survive: the file ends up under its new name with the edit in it.
- A delete and an edit: the edit wins — the file comes back with the change rather than losing your work.
- Frontmatter (
status,pov, …) merges field by field, so changingstatuson one device andpovon the other keeps both and never produces a half-merged, broken block. If both change the same field, one value wins on both devices. - A rename of a whole folder moves the folder everywhere, and its settings (role, order, metadata) and bookmarks come with it.
- Story cards merge card by card and field by field: cards added on both devices are all kept, and editing a card’s cause on one device and its effect on the other keeps both. A card’s link to a scene follows that scene when it’s renamed, even if the card was linked under the old name on a device that hadn’t heard about the rename yet. (A link to a name that more than one document shares stays as it is.)
- Two devices creating a file at the same path keeps both: one gets a name like
Scene (conflict 3f9a1c2e).md.
The file you’re editing
While a file has unsaved edits in the editor, Smaragd holds off writing other devices’ changes to it, so your typing is never disturbed. When you save, your edit is merged with whatever arrived, and the merged text appears. A file you have open but haven’t changed simply reloads when another device changes it, like any file changed outside the editor.
Joining with a project that already has files
Setting up a second device with a copy of the project (from a backup, a zip, a cloud folder) is fine:
- Files that are identical to the vault’s are simply recognised — nothing is duplicated.
- If a file differs from the vault’s, there’s no way to know which is newer, so both are kept: the vault’s version takes the original name, and your local version is saved next to it as
name (conflict copy).md. Smaragd tells you when this happens. Compare the two and merge by hand. - If your
project.jsondiffers, the vault’s settings are used and your previous file is kept as.smaragd/project.json.before-sync.
Your passphrase
- It’s chosen by you, entered in Settings > Sync, and must be identical on every device. Choose something long — it’s the only thing protecting your data if someone gets the server’s files. Smaragd won’t create a vault with a passphrase shorter than 12 characters, one that repeats a few characters, or one that is just a number, and Settings warns while you type one. A few unrelated words make a good one.
- It never leaves your device — the server never sees it — and it cannot be recovered. If you lose it, the copy of your project on the server can’t be decrypted, by anyone, including whoever runs the server. Your own files are not affected: they are plain Markdown on your devices, so nothing is lost as long as one device still has them. Keep the passphrase somewhere safe, like a password manager.
- Changing it makes existing vaults unreadable (the server’s copy was encrypted with the old one); your local files are untouched. If sync stops with a message about the passphrase, the passphrase on this device doesn’t match the one the vault was created with. To switch to a new passphrase, choose Stop syncing this project on each device, then create a fresh vault from one of them and join the others to it.
- Like your other settings, it’s kept as plain text in Smaragd’s settings file (
smaragd.toml), at the same trust level as the project files on this disk. The file (and this device’s sync credentials) can be read only by your own user account. A full-disk encryption setup is a good idea on a laptop.
What the server can and can’t see
It can’t see: file names, folder structure, your text, your project settings — all of it is encrypted with a key built from your passphrase on your device. It also can’t swap one document’s data for another’s without the change being detected.
It can see that a vault exists, how many documents it has (as random ids), how big and how frequent the updates are, which of your devices made them, and your IP address. Device access tokens and pairing codes are stored on the server only as hashes.
It can do harm only by withholding or deleting data (so keep your backups on) — it can’t read or forge your content.
On your own devices nothing is encrypted by Sync. Your Markdown files are plain files, and Smaragd’s local sync bookkeeping (in its data folder, next to the backup folder) contains readable copies of your document text, including earlier revisions, so it deserves the same protection as the project itself — full-disk encryption is the right tool for that.
Files on your side: a small, non-secret file .smaragd/sync.json in the project says which vault it belongs to (it’s safe to commit or copy); this device’s access token and sync bookkeeping live in Smaragd’s data folder, outside the project, so they never end up in git or a backup. The token only ever goes to the server this device paired with: if sync.json is changed to name another server (say, by someone else pushing to the project’s git repository), Smaragd ignores that, keeps syncing with the original server and says so in the Sync panel. To really move a project to a new server, choose Stop syncing this project and pair again.
Sync is not a backup
Sync copies every change, including a mistake or a deletion, to all your devices. It keeps no history you can go back to. Keep backups (and optionally git) switched on as well. Sync and git can be used together — git commits whatever is currently on disk, and sync moves whatever is on disk between devices — but see below for ways that combination can still bite you.
Sync and git don’t always mix cleanly
Sync moves whatever is currently on disk; it has no idea about git history, and git history itself isn’t synced — each device keeps its own independent set of commits over the same files. That mostly works, but watch for:
- Unresolved git conflict markers get synced too. If a
git pullon one device leaves a file with unresolved<<<<<<</=======/>>>>>>>conflict markers in it, Sync treats that just like any other edit and copies it to every other device. Smaragd’s one-time sanity check, run right after a project opens, flags any document still containing them, but it’s still worth resolving a git conflict before your next sync pass rather than after. - Git history can diverge between devices. Because commits aren’t synced, two devices can build up their own separate commit history over the same, sync-kept-identical files — more likely with auto-commit switched on. Pushing both histories to the same remote, or pulling one into the other, needs an ordinary git merge to reconcile them; Sync only keeps the files in step, not the commits.
- An automatic commit can capture someone else’s change. Auto-commit fires on its own timer, independent of when a sync pass lands. That’s harmless in itself — git just commits whatever happens to be on disk — but a commit you expect to record your own edit can sometimes also pick up a change that just arrived from another device.
If you rely on both, keep backups on regardless, and treat conflict markers and diverging git history as things to watch for yourself — Sync doesn’t resolve either for you.
If you run the server
The server’s own self-hosting guide has the details; the short version of what to expect:
- It looks after itself. It clears out expired pairing codes, deletes vaults whose last device left 30 days ago (adjustable), and keeps its database file small, all in the background.
smaragd-sync-server admin listshows every vault, andadmin delete-vault,purge-emptyandvacuumclean up by hand; run them withdocker exec(or directly, without Docker) while the server is running. - You still need to back up its data volume, install updates, and watch disk space. Deleted files’ encrypted history stays on the server until its vault is deleted.
Good to know
- The vault stays compact. As a file accumulates changes, Smaragd periodically replaces the old ones on the server with a single snapshot, so the vault doesn’t grow without bound and a new device catches up quickly. There’s also a per-vault size limit on the server (1 GiB by default).
- Bookmarks point to a line number, so if two devices edit above a bookmarked line at the same time, the bookmark may end up a line or two off.
- One vault per project, and a project remembers the server it was paired with; the server in Settings is used when you create or join.
Troubleshooting
- “The sync passphrase doesn’t match this vault” — the passphrase here differs from the one used when the vault was created. Correct it in Settings > Sync; sync restarts by itself.
- “This device was removed from the vault” — another device revoked it, or the vault was deleted. Choose Stop syncing this project, then join again with a new ticket if you want.
- Create Vault says the server only lets its administrator create vaults — enter the server’s admin token when asked (it’s set by whoever runs the server). If you run the server yourself and have lost the token, the server’s self-hosting guide shows how to look it up or set a new one; existing vaults are unaffected.
- “That doesn’t look like a pairing ticket” — copy the whole ticket, with nothing added or missing. Tickets are single-use and expire after 10 minutes; make a new one if in doubt.
- “The last pass failed: … vault is full” — the vault has reached the storage limit set by whoever runs the server (1 GB by default). Smaragd already compacts old history on its own, so a vault that is still full holds that much current material; the server’s operator needs to raise its quota (
SMARAGD_SYNC_VAULT_QUOTA_MB). Nothing is lost meanwhile: your edits wait on this device and go up once there is room. - “… has a change too large to upload” — a single save added more than about 8 MB to one document (for example a very large paste, or an image pasted in as text), which is more than the server accepts in one piece. Ordinary writing never comes close — 8 MB is over a million words. Only that document stops syncing; everything else carries on, and your other devices show it as an empty file for now. Remove the oversized content and save — it then syncs normally again, with nothing lost. Until you do, the Sync panel keeps the warning up.
- A file doesn’t sync, and the Sync panel says it’s too large — it’s over the server’s per-file limit. Ask whoever runs the server to raise
SMARAGD_SYNC_MAX_FILE_MB, or keep the file out of the project folder. - Offline — check the host, port and HTTPS setting with Test Connection, and that the server is running.
- A
(conflict copy)or(conflict …)file appeared — two devices made different changes that couldn’t be told apart; open both files, keep what you want, and delete the other.
Plugins
Smaragd can be extended with small scripts written in Rhai, an embedded scripting language. A plugin script can:
- Register a custom
:command - Define an
on_save(text)hook that transforms a document’s text right before an explicit save
Where Plugins Live
- Global, always loaded:
plugins/inside smaragd’s config directory- Linux:
~/.config/smaragd/plugins - macOS:
~/Library/Application Support/smaragd/plugins - Windows:
%APPDATA%\smaragd\config\plugins
- Linux:
- Per-project (never synced between devices by Sync, and the switch below stays per-device):
.smaragd/plugins/inside the project folder. This only loads once you explicitly turn it on for that project viaTools > Enable Project Plugins— a project folder shared or pulled from somewhere else could otherwise run unreviewed code the moment you open it.
Use Tools > Reload Plugins to pick up new or edited scripts without restarting the app. A script that fails to compile or run, or that tries to register a : command another plugin already owns, is skipped with an error message — it never stops other plugins from loading.
⚠️ No Sandbox
A loaded plugin can shell out to any program on your system, with the same access as anything else run under your own user account — there’s no restricted execution environment. Only load plugins whose code you trust, and treat the project-plugin opt-in as a real trust decision, not a formality.
Host Functions Available to a Script
smaragd_status(msg)— showmsgin the status barsmaragd_document_text()— returns the open document’s current textsmaragd_document_basename()— returns the open document’s file name (without its.mdextension), or an empty string if nothing’s opensmaragd_document_filename()— returns the open document’s path relative to the project root,.mdextension included (e.g.Part 1/Scene 5.md), or an empty string if nothing’s opensmaragd_set_document_text(text)— replaces the open document’s textsmaragd_run_command(cmd, args)— runscmd(an array of stringargs) as a subprocess, waits for it to finish, and returns a map withstdout,stderr,exit_code, andsuccess. Runs in the open project’s root, and blocks the app’s UI until the process exits — avoid anything long-running.register_command(name, fn_name)— called once at script load time to expose a:commandregister_shortcut(name, key_spec)— called at script load time to give a registered:command a default keyboard shortcut, e.g.register_shortcut("hello", "ctrl+shift+h").key_specis+-separated modifiers (ctrl/cmd/command,shift,alt/option— case-insensitive) followed by a key name (k,F2,Enter,Colon, …). A bare key with no modifier is rejected unless it’s a function key or Escape, same rule as built-in shortcuts.
Whatever shortcut a script asks for is just a default: File > Settings lists every plugin command that registered one, alongside the built-in shortcuts, and lets you remap or unbind it exactly the same way. If a script’s requested combo is already in use by a built-in action or another plugin command, it’s simply left unbound (with a message explaining why) rather than stealing it — you can still assign it a free combo yourself from Settings.
Examples
A custom : command
fn say_hello(arg) {
smaragd_status("Hello, " + arg + "!");
}
register_command("hello", "say_hello");
register_shortcut("hello", "ctrl+shift+h");
Typing :hello world in the command prompt calls say_hello("world") and shows “Hello, world!” in the status bar. Everything after the command name is passed as a single string argument. Pressing Ctrl+Shift+H runs the same command with an empty argument.
Shelling out to a tool
fn wordcount(arg) {
let result = smaragd_run_command("wc", ["-w"]);
smaragd_status("Words: " + result.stdout);
}
register_command("wordcount", "wordcount");
An on_save hook
fn on_save(text) {
text.trim() + "\n"
}
This runs before every explicit save (:w / Ctrl+S / :wq), in plugin-load order, each hook’s output feeding the next. Return a String to replace the saved text; return anything else (typically nothing) to leave it unchanged. If a hook throws, that plugin’s change is dropped and an error is shown — a broken plugin can never block a save.
Note: on_save only runs on those explicit save actions — not the focus-loss autosave, and not the save-before-switching-documents path.
Git Integration
Git works alongside Sync: git commits whatever is on disk at that moment, while sync moves the same files between your devices. Sync’s own bookkeeping (your device’s access token and state) is kept outside the project folder, so it never lands in a commit. The two don’t coordinate with each other, though — see Sync and git don’t always mix cleanly for the ways that can cause real conflicts.
Versions menu, or :git commands:
- Opt-in per project — you’re offered “Enable Git Support” once when a project is opened, or you can trigger it manually (
Versions > Enable Git Supportor:git enable) - Commit (
Ctrl+Alt+C) / Commit and Push (Ctrl+Alt+Shift+C) / Push (Ctrl+Alt+P) / Pull (Ctrl+Alt+L) — shells out to the systemgitbinary - Push and pull run on a background thread, so a slow or hung network operation never freezes the UI
- A file with uncommitted changes gets a trailing “•” marker in the Binder — folders show the same marker if anything nested inside them is dirty
The Commit dialog
Confirming Commit or Commit and Push opens a multi-line message box, pre-filled from the commit message template below — edit it freely before confirming. Ctrl+Enter or the button commits (plain Enter inserts a newline instead, since the template’s body commonly lists every changed file).
Commit message template
File > Settings > History has a Commit message template — a multi-line text box used both for the Commit dialog’s pre-filled message and for every automatic commit (see Auto-commit below), with placeholders filled in each time:
| Placeholder | Value |
|---|---|
{{date}} | Today, formatted per Settings > Templates |
{{time}} | Current time, HH:MM (24-hour) |
{{numFiles}} | Number of dirty files |
{{linesAdded}} | Lines inserted |
{{linesDeleted}} | Lines deleted |
{{linesChanged}} | Lines inserted + deleted |
{{fileList}} | One line per changed file, A/M/D followed by its path (added/changed/deleted) |
The default template is:
Smaragd backup
{{fileList}}
— so out of the box every commit’s body lists what changed, without you having to discover {{fileList}} yourself. The Settings page shows a live preview and a quick-reference table of every placeholder.
Auto-commit
File > Project Settings > Git (see Project Settings) can commit automatically on an interval, per project:
- Automatically commit changes — off by default
- Every N minutes — how often (default 15)
- Push after each automatic commit — off by default; independent of the interval, so you can auto-commit locally without ever auto-pushing
An automatic commit uses the same template and rendering as a manual one, and reuses the manual Commit path exactly — “nothing to commit” is silently skipped, and a failure surfaces the same error toast a manual commit would. It never fires the moment a project opens (the timer starts counting from when you opened it, not from some earlier session), and it steps aside if a push/pull you triggered manually is already in flight.
Version Activity
Versions > Version Activity (Ctrl+Alt+V) is a dockable tab with three sections:
- Dirty files — the same set that drives the Binder’s “•” marker, listed out.
- Recent commits —
git log’s last 20 commits: short hash, subject, author, and relative date. - Activity — a running log of what smaragd itself did via git this session (commits, pushes, pulls, both manual and automatic), each with an outcome (success, “nothing to commit,” or an error) and how long ago. A push or pull entry expands to list the files it actually transferred. Cleared when you close the project or open another one; not saved to disk.
A Refresh button re-reads dirty files and the commit log on demand, for changes made outside the app (e.g. a git commit from a terminal).
Global on/off switch
File > Settings > History also has an app-wide “Enable Git integration” switch — a stronger, global kill switch on top of the per-project opt-in above. Off by default for a brand new install (on by default for anyone upgrading from a version before this setting existed, so it never silently turns git off under you). Turning it off hides the Versions menu entirely (Version Activity included), makes every git shortcut and :git command a no-op, drops the Git rows from the Shortcuts settings, removes git from the command-prompt’s autocomplete, and skips the one-time “enable git support?” prompt when opening a project.
Backups
Backups are your safety net for mistakes: Sync (experimental) copies every change — including a deletion — to all your devices, so it is not a substitute for them.
Modeled on Scrivener’s own automatic backup scheme. File > Settings > History:
- Off by default — a master “Enable automatic backups” switch, plus independent triggers for backing up when opening a project, when closing a project, and on every manual save (
Ctrl+S/:w/:wq— not the silent autosave that runs on losing focus or switching documents) - Each backup is a zipped, timestamped snapshot of the whole project folder —
{project name}-{YYYY-MM-DD-HHMMSS}.zip— written to one shared backup folder (defaulting to the platform’s data directory, browsable to somewhere else, with a Reset button to go back to the default) rather than inside the project itself, so it survives the project folder being moved or deleted - Multiple projects share the same backup folder; each project’s own backups are told apart by their filename prefix, so keeping or pruning one project’s backups never touches another’s
- A backup includes everything under the project folder that isn’t excluded by a
.gitignore/.ignorefile — including.smaragd/(manuscript ordering, folder roles, story cards, and the rest of the project’s own metadata) — but always skips.git, since that’s redundant with git’s own history and often the single largest thing in the folder - Backups to keep (1–100, default 10) caps how many of a project’s own snapshots are kept; the oldest are deleted once a new backup pushes past that count
- A failed backup shows as an error toast and never blocks whatever you were doing (opening/closing a project, saving) — a backup is a safety net, not a precondition for those
- There’s no in-app restore, and no manual “back up now” action — only the three triggers above. To restore a backup, unzip it somewhere and open the resulting folder as a project (
File > Open Project) the normal way
Themes and Appearance
Two independent settings:
- Appearance (
File > Settings, or:dmode <dark|light|system>): plain Dark/Light/System styling. System follows your OS preference and updates immediately. - Color Theme (
View > Theme, or:theme <id>): a full Helix-inspired palette layered on top of the appearance base.:themewith no argument clears back to plain appearance styling.
Since the editor is a single plain-text field with no syntax-highlighting pipeline, each theme reproduces its palette’s overall look (background, body text, one accent color for selection/links) rather than full per-token syntax highlighting.
Built-in themes
| id | Label |
|---|---|
gruvbox | Gruvbox |
gruvbox_light | Gruvbox Light |
dracula | Dracula |
nord | Nord |
nord_light | Nord Light |
solarized_dark | Solarized Dark |
solarized_light | Solarized Light |
catppuccin_mocha | Catppuccin Mocha |
catppuccin_latte | Catppuccin Latte |
onedark | One Dark |
onelight | One Light |
tokyonight | Tokyo Night |
everforest_dark | Everforest Dark |
everforest_light | Everforest Light |
ayu_dark | Ayu Dark |
Custom themes
You can add your own themes as .toml files — no in-app editor, the same “drop a file in a folder” model as Plugins. Custom themes live in smaragd/themes/ inside smaragd’s config directory (the same base path as the global plugins folder):
- Linux:
~/.config/smaragd/themes - macOS:
~/Library/Application Support/smaragd/themes - Windows:
%APPDATA%\smaragd\config\themes
A minimal custom theme:
id = "my_theme"
label = "My Theme"
dark = true
background = "#1e1e2e"
foreground = "#cdd6f4"
accent = "#cba6f7"
id, label, dark, and the three colors are required; colors are "#RRGGBB" hex strings (the # is optional). id is what you’d type as :theme my_theme — it’s lowercased automatically, so casing in the file doesn’t matter.
An optional fourth color, broken_wikilink, sets the color a [[wikilink]] renders in (Editor and Preview alike) when its target doesn’t match any document in the project. Omit it and it falls back to a plain default red:
broken_wikilink = "#f38ba8"
Use View > Theme > Reload Custom Themes to pick up a new or edited file without restarting the app. A theme file that fails to parse, has an invalid color, or whose id collides with an already-loaded theme (built-in or another custom one — whichever loaded first wins) is skipped with an error message rather than stopping other themes from loading. If the theme you currently have active stops resolving after a reload (for instance, you just introduced a mistake into the file you’re editing), smaragd falls back to the default appearance rather than leaving a stale palette applied with nothing in the menu showing as selected.
Editor Font
File > Settings has a Font section with a font and size for the Editor. (The Preview tab’s fonts come from the selected typesetting style instead — see Markdown Preview — so this setting no longer affects Preview; to resize Preview’s text on the fly without changing that style, see Zooming.)
| Font | What it looks like |
|---|---|
| Proportional | egui’s built-in sans-serif — the default |
| Monospace | egui’s built-in fixed-width face |
| Libertinus Serif | A literary serif text font — the same one used by the Trade Paperback export style |
| DejaVu Sans Mono | A fixed-width face — the same one used by the Manuscript export style |
| Atkinson Hyperlegible | A sans-serif designed by the Braille Institute for readability, particularly for low-vision readers — the same one used by the Large Print export style |
These five are the only choices — not a live picker over every font installed on your system, so the app looks and behaves identically on every platform. A typesetting style naming one of these by name ("Libertinus Serif"/"DejaVu Sans Mono"/"Atkinson Hyperlegible") renders in Preview with the real font; any other name falls back to a default face for on-screen preview purposes only — the exported DOCX/EPUB/PDF still use the real font name.
The Appearance settings category has a separate UI font picker — the same five choices as above, but for the rest of the app’s chrome (menus, the Binder, buttons, headings) instead of the Editor/Preview specifically. It defaults to Proportional (egui’s own default), so nothing changes until you pick something else.
Keyboard Shortcuts
All shortcuts are fully remappable in File > Settings, listed with a Category column (Application, Project, Files & Folders, Editing, View, Git, Tools) and sorted by category, then alphabetically within each. Defaults below use Ctrl (shown as Cmd on macOS):
| Action | Default shortcut |
|---|---|
| New Project | Ctrl+Alt+N |
| Open Project | Ctrl+O |
| Close Project | Ctrl+Shift+W |
| Settings | Ctrl+, |
| Project Settings | F4 |
| Exit | Ctrl+Q |
| Toggle Preview | Ctrl+Shift+P |
| Save | Ctrl+S |
| New File | Ctrl+N |
| New Folder | Ctrl+Shift+F |
| Rename | F2 |
| Delete | Ctrl+Shift+Backspace |
| Restore | Ctrl+Shift+R |
| Toggle Dark/Light Mode | Ctrl+Shift+D |
| Toggle Full Screen | F11 |
| Find and Replace | Ctrl+F |
| Toggle Corkboard | Ctrl+Shift+K |
| Toggle Story Grid | Ctrl+Shift+G |
| Toggle Belief Timeline | Ctrl+Shift+E |
| Cycle Binder Color Mode | Ctrl+Shift+C |
| Toggle Document Stats in Binder | Ctrl+Alt+D |
| Toggle Backlinks | Ctrl+Shift+B |
| Toggle Source/Reading View | Ctrl+E |
| Toggle Backlinks in Document | Ctrl+B |
| Toggle Tags | Ctrl+Shift+T |
| Command Prompt | Ctrl+: |
| Commit (Git) | Ctrl+Alt+C |
| Push (Git) | Ctrl+Alt+P |
| Pull (Git) | Ctrl+Alt+L |
| Commit and Push (Git) | Ctrl+Alt+Shift+C |
| Metadata | Ctrl+Shift+M |
| Activate Wikilink | Ctrl+Enter |
| Toggle Binder/Editor Focus | F6 |
| Toggle Focus Mode | F9 |
| Open Document | Ctrl+P |
| Close Document | Ctrl+W |
| Recent Files | Ctrl+Shift+O |
| Go Back | Alt+Left |
| Go Forward | Alt+Right |
| Toggle Pomodoro Timer | Ctrl+Alt+T |
| Toggle Word Count | Ctrl+Alt+W |
| Refresh Word Count | F5 |
| Toggle Collaboration Panel | Ctrl+Shift+L |
| Toggle Streak Tracking | Ctrl+Alt+S |
| Toggle Dashboard | Ctrl+Alt+G |
| Toggle Bookmark | Ctrl+F2 |
| Toggle Bookmarks | Ctrl+Alt+B |
| Next Bookmark | Alt+Down |
| Previous Bookmark | Alt+Up |
| Add Note at Cursor | Ctrl+Shift+J |
| Toggle Notes | Ctrl+Shift+N |
| Next Note | Ctrl+Alt+Down |
| Previous Note | Ctrl+Alt+Up |
| Zoom In Preview | Ctrl++ |
| Zoom Out Preview | Ctrl+- |
| Reset Preview Zoom | Ctrl+0 |
| Toggle Spell Check | F7 |
| Search Everywhere | Ctrl+Shift+A, or tap Shift twice |
| Toggle Sync Panel | Ctrl+Shift+Y |
| Sync Now | Ctrl+Alt+Y |
| Toggle Version Activity | Ctrl+Alt+V |
| Open Today’s Daily Note | F8 |
Two shortcuts can never overlap — rebinding one to a combo another action already owns automatically un-assigns it from the previous owner. This holds across built-ins and plugin shortcuts alike: if a loaded plugin registered a : command with its own shortcut (see Plugins), it shows up in its own “Plugin Shortcuts” section further down the same window, remappable/unbindable the same way.
Notifications
Smaragd tells you about things two different ways, depending on how much attention they need:
- Toasts — a stack of boxes in the top-right corner of the window, each with its own × to dismiss early, that fade away on their own after a few seconds otherwise. Used for anything that represents an actual problem: a failed save, export, or git operation; invalid frontmatter YAML (see Document Metadata); a plugin error; and so on. Several can stack up at once if more than one thing goes wrong in quick succession.
- The status bar, at the bottom of the window — a single line for routine confirmations that don’t need to grab your attention: “Committed”, “Exported to …”, “Replaced 3 occurrence(s)”, and the like. It now clears itself automatically after a few seconds, rather than sitting there until the next unrelated status update happens to overwrite it.
Both durations are configurable — see Notifications under Settings below.
Spell Check
Smaragd underlines words it doesn’t recognize while you type, in the editor’s warning color. Right-click an underlined word for a menu of Hunspell’s own correction candidates — click one to replace the word on the spot — plus an “Add to Dictionary” entry for names and invented words that keep getting flagged: adding one stops it being underlined immediately, everywhere, and the word is remembered across restarts (Settings > Spell Check doesn’t currently show or let you remove this list — for now, undoing an accidental add means editing spell_check_custom_words in smaragd.toml by hand).
It’s off by default. Turn it on in Settings > Spell Check (Ctrl+,) with the Language dropdown.
After that, Tools > Toggle Spell Check (or F7, or :spell in the command prompt) turns it off and back on without going through Settings. Each project remembers the last language used in it, so toggling spell check back on in a Norwegian manuscript brings back Norwegian even if you were writing English in another project in between. In a project where spell check has never been used, toggling on asks you to pick a language in Settings first.
In Focus Mode, next to the language picker, controls spell check while Focus Mode is active: Keep current (the default) leaves it alone, Off hides the underlines for a distraction-free draft, and On turns it on in the current language, or the project’s last language if it’s off. F7 still works inside Focus Mode, and leaving Focus Mode restores what you had before.
Smaragd ships with only tiny placeholder word lists (a few dozen words each), just enough to prove the feature works — not enough to be useful. Below the language picker, Dictionaries lists every supported language with a Download button: clicking it fetches a real, individually license-reviewed Hunspell dictionary into your own data directory (never bundled into the app itself), verified by SHA-256 against a tracked catalog before being kept. A downloaded dictionary is used immediately, no restart needed. Twenty languages are available at launch: English (American), English (British), German, Dutch, Norwegian Bokmål, Norwegian Nynorsk, French, Spanish, Italian, Portuguese (Brazil), Portuguese (Portugal), Swedish, Danish, Polish, Russian, Georgian, Lithuanian, Persian, Turkmen, and Interlingue.
See Settings below for where this fits among the other categories.
Settings
File > Settings (or Ctrl+,) is a two-pane dialog, IntelliJ-style: a category list on the left (General, Appearance, Editor, Templates, History, Spell Check, Sync, Pomodoro, Shortcuts), Up/Down to move between categories, and that category’s controls on the right. Settings are stored as smaragd.toml in the platform’s config directory (the same base path as the global plugins, custom-themes, custom-styles, and custom-project-templates folders — see Plugins, Custom themes, Typesetting styles, and Project Templates). Writing Streak is not here — it’s configured per project, inside its own dock tab (see Writing Streak); other per-project settings (git auto-commit, syncing non-Markdown files, binder coloring) live in their own dialog — see Project Settings.
- General: Reopen project on launch (off by default; restores the open document, cursor, binder state and window too — see Projects), Ensure Research and Trash folders exist in every project (off by default; see Projects), and a Notifications section with Error toast duration and Status bar message duration (1–60 seconds each, defaulting to 6 and 8 respectively — see Notifications above)
- Appearance: Dark/Light/System and Color Theme (see Themes), a UI font picker (see Editor Font), UI Scale — a manual multiplier (50%–300%, default 100%) on top of whatever scaling your OS/display server already reports, for the rare case that comes back wrong (some Wayland compositors don’t report a scale winit picks up, leaving the whole UI tiny with no apparent way to fix it; takes effect immediately, Reset clears it back to 100%) — and Show document stats in binder (off by default; see The Binder)
- Editor: font + size (see Editor Font), Typewriter quotes in Preview and export (off by default; see Typewriter Quotes), Show line numbers (off by default; see Writing and the Editor), and Allow multiple documents open at once (off by default; see Writing and the Editor)
- Templates: date format for
${{date}}— see Template Variables - Spell Check: a Language dropdown (off by default), an In Focus Mode dropdown (keep current, on or off) and a Dictionaries list to download the ones you want to use — see Spell Check
- History: an app-wide “Enable Git integration” switch and a multi-line commit message template with a placeholder quick-reference and live preview (see Git Integration), and a Backups section (see Backups) — Scrivener-style automatic zipped snapshots of the whole project, off by default. A master “Enable automatic backups” switch, plus independent triggers for opening a project, closing a project, and every explicit save, a backups to keep count, and a backup folder (defaulting to the platform’s data directory, browsable to somewhere else)
- Sync (experimental): the on/off switch for Sync, the sync server’s Host, Port, Path and Use HTTPS settings, your end-to-end encryption Passphrase (masked; the same on every device, stored in plain text in the settings file, which only your user account can read, and not recoverable if lost; at least 12 characters to create a vault), this device’s Name, and a Test Connection button. Pairing a project with a vault is done from the Sync panel, not here.
- Pomodoro: durations (work/short break/long break minutes, and sessions before a long break), plus a desktop-notification toggle for automatic phase completions — see Pomodoro Timer
- Shortcuts: remap or unbind any action, including a fullscreen toggle
If the settings file is missing or its contents can’t be parsed, smaragd falls back to defaults rather than failing to start.
Project Settings
File > Project Settings… (or F4) is a two-pane dialog, structured just like the app-wide File > Settings (see Settings) — a category list on the left, that category’s controls on the right — but scoped to the open project rather than app-wide, and disabled with no project open. It’s grouped in the File menu right next to Settings.
- Git: Automatically commit changes, an interval in minutes, and Push after each automatic commit — see Auto-commit. Grayed out (with an explanatory note) unless git integration is on both app-wide and for this project.
- Sync: Also sync images, PDFs and other files — see Images, PDFs and other files. Pairing, live status, and the device list stay in the Sync dock tab; this is the one actual setting, not a status or action.
- Binder: the same Off / Status / POV / Word Count Progress choice as
View > Color Binder By— see Binder Background Coloring. An additional, discoverable home for the same setting; the binder’s own right-click menu and the status-bar indicator still work too. - Daily Notes: off by default — the enable toggle, folder, filename format, and optional template for today’s note — see Daily Notes.
More project-scoped settings will likely land here over time, the same way the app-wide Settings dialog grew its own categories.