Build Ulysses
YESreplaces $5.99/mosaves $71.88/yrback to the verdict
A writing environment over a folder of Markdown files: a sheet library with groups and filters, a typewriter-style editor, word and character goals with honest progress, optional editing passes shown as a diff, and export to formatted documents with the source always readable elsewhere.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Builds the front end and the tooling.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - installfree
Why Tauri compiles the desktop shell and the file watcher.
Get it rustup from rustup.rs, plus the platform packages Tauri lists. open ↗
Verify
A Tauri hello world builds and runs - installfree
Why Phase 5 turns Markdown into the formats people actually accept. Writing a converter is not the project.
Get it Install pandoc or an equivalent, plus a typesetting engine if you want PDF output.
Verify
A test Markdown file converts to your target format - have readyfree
Why Ordering, search and goals are all trivial at five sheets and revealing at fifty, and compile order in particular fails only at scale.
Get it Use your own writing, or split a long public domain text into sheets.
Verify
The library loads and its sheet count is reported - installfree
Why Phase 6 verifies the library reads without this application, which is the ownership claim and cannot be tested with the application that wrote it.
Get it Any general Markdown editor you already have.
Verify
The library folder opens and sheets read correctly
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- sheets(id, path, title, group_id, position, word_count, char_count, mtime, content_hash) · one Markdown file each - groups(id, parent_id, name, position) · directories on disk, so the structure is visible outside the application - goals(id, target_kind, target_value, scope_kind, scope_id, deadline) · scope is a sheet or a group - sessions(id, started_at, ended_at, words_added, sheet_id) · writing sessions, which is what progress is actually made of - keywords(id, name), sheet_keywords(sheet_id, keyword_id) · stored in front matter so they travel with the file - Groups are directories and keywords are front matter, so the organisation survives without this application.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
LIBRARY_PATH | required | ~/Writing/Library | The folder of Markdown files. Your data, in your backup. |
INDEX_PATH | required | ~/.local/share/write/index.db | Search and goals. Deliberately outside the library so syncing cannot corrupt it. |
SAVE_DEBOUNCE_MS | required | 400 | How long after typing before writing. Lower loses less on a crash. |
EXPORT_DIR | required | ~/Writing/Exports | Where compiled documents are written. Never the library folder. |
GRAMMAR_ENDPOINT | optional | http://localhost:8081 | Optional local grammar service. Leave unset and the editing passes are disabled entirely. |
The build, in order
A library over a folder
Your Markdown files appear as a browsable library, and the structure on disk matches what you see.
The structure on disk is the structure in the application. No hidden database-only organisation.
Files
src/library.tsterminalnpm create tauri-app@latest
So they travel with the file and are visible in any editor.
Files
src/frontmatter.tsHash what you write and ignore your own events, or the watcher will reload under the cursor.
Files
src/watcher.ts
done when · tick each as it passeswatch out- Deriving a sheet's title from its filename and then letting the user rename the title in the interface creates an ambiguity: does the file move? Decide explicitly, put the title in front matter, and leave filenames alone unless the user renames them deliberately.
An editor that stays out of the way
Writing feels quiet, and nothing is ever lost.
Highlighting rather than rendering. A rich text surface fights Markdown and loses.
Files
src/editor.tsTemporary file plus rename. Test by killing the process mid-save.
Files
src/save.tsIncrementally or off the main thread. Recounting a long sheet on every keystroke is felt immediately.
Files
src/count.ts
done when · tick each as it passeswatch out- Writing directly over the file means a crash mid-save can truncate a chapter, which for a writer is the worst possible failure. Write to a temporary file and rename over the target, which is atomic and cannot leave a half-written sheet.
Goals that are honest
Progress is measured from what you actually wrote, including the days you did not.
Both numbers. A day of cutting is progress and the interface should not disagree.
Files
src/sessions.tsSheet or group, computed from current counts rather than a running total that can drift.
Files
src/goals.tsNo streaks, no grades, no red. A missed deadline is a fact, not a verdict.
Files
src/ui/Goal.tsx
done when · tick each as it passeswatch out- Counting net words means a day spent cutting shows as negative progress, which is exactly backwards: editing is writing. Track words added and words removed separately, and show both rather than a single number that punishes revision.
Editing passes with a visible diff
Suggested changes are shown before they are applied, and the original survives.
A local grammar service keeps the manuscript on the machine. Say clearly if any pass does not.
Files
src/passes/Sentence-level diffs on prose are unreadable. Word level with sentence grouping is what a writer can judge.
Files
src/diff.tsOn the suggestion record, so acceptance is reversible beyond undo.
Files
src/suggestions.ts
done when · tick each as it passeswatch out- Applying a change directly and relying on undo loses the original as soon as anything else is typed, and a writer who accepts a rewrite and then dislikes it has no way back. Store the original with the suggestion, so acceptance remains reversible beyond the undo stack.
Export
A group of sheets becomes one formatted document, and the source is untouched.
The stored position, not the filename. Test with a group where the two disagree.
Files
src/export.tsInclude or exclude, so drafts and notes can live in the same group as the manuscript.
Files
src/export.tsChecksum before and after as a test.
Files
src/export.test.ts
done when · tick each as it passeswatch out- Compiling in filesystem order rather than the library's explicit order will reorder a book, and the mistake is invisible until someone reads the export. Store an explicit position and use it, since alphabetical filenames stop working at chapter ten.
Sync, backup and leavingproduct builder
The library moves between machines, and leaving costs nothing.
Version control gives history and explicit conflicts; a sync drive is simpler and hides them.
Files
README.mdWatch for the naming patterns sync tools produce and list them as sheets needing attention.
Files
src/conflicts.tsOutside, disposable, rebuildable. Verify the rebuild produces identical results.
Files
src/index.ts
done when · tick each as it passeswatch out- Putting the search index inside the synced folder means two machines fight over the same database file and corrupt it. Keep it outside, and treat it as disposable so a corruption is a rebuild rather than a loss.
That is the whole plan for Ulysses. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- The native polish of the commercial application.
- Built-in sync and mobile applications.
- Publishing integrations.
- A decade of library management refinements.
- native Apple polish, iCloud sync, mobile apps, and publishing integrations
- cross-device sync
- large proprietary style models
- browser and office-suite extensions
- team style guides
- Split view for writing against notes, which is the most missed feature in a single-pane editor
- Revision history from version control surfaced in the interface
- Custom export styles as files, so a manuscript format is version controlled
Need the files? The project pack on the verdict page hands your agent the whole brief · more writing tools.