Build Dabble
KINDAreplaces $19/mosaves $228/yrback to the verdict
A novel workspace whose hard problems are that the manuscript must survive the application, that plot threads have to stay attached to scenes through reordering and splitting, and that an export has to satisfy a specification before anybody will sell it.
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 The file layer is where atomic writing and snapshotting live, and it is the part that must not be approximate.
Get it rustup, then the platform prerequisites listed by the Tauri project. open ↗
Verify
A blank application builds and runs on your machine - installfree
Why Builds the front end and runs the test suite.
Get it nodejs.org or your version manager. open ↗
Verify
node --version prints v22 or higher - installfree
Why Without it the export phase is guesswork, and the file will be rejected by somebody else's upload form instead of by your own build.
Get it Use the validation tool published for the format and pin its version in the repository.
Verify
A deliberately broken export fails and a good one passes - have readyfree
Why Every problem in this build is a problem of scale: reordering, orphaned beats, counting disagreements and export timing all look fine on a ten scene fixture.
Get it Use your own work in progress, or a public domain novel split into scene files.
Verify
Index rebuild, grid render and export all complete within a stated time - decidefree
Why Deciding it after implementation means the rule is whatever the code happened to do, and the number will disagree with a submission form for reasons nobody can explain.
Get it Write down how hyphenated compounds, contractions, numerals and dialogue punctuation are treated, then implement that.
Verify
A fixture counts exactly as the document says it should
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- Scene files on disk with front matter(id, title, pov, status, updated_at) · the file is the record and everything else is derived from it - scene_index(id, path, ordinal, chapter_id, title, words, hash, indexed_at) · rebuilt by rescanning the folder, and safe to delete at any time - snapshots(id, scene_id, at, path, bytes, reason) · taken before every replace and on a timer, with a stated retention - threads(id, name, colour, notes) and beats(id, thread_id, scene_id, ordinal, note) · the plot grid, keyed on scene identifier and never on position - characters(id, name, notes, first_scene_id) and places(id, name, notes) · the continuity notes that a long manuscript cannot hold in one head - sessions(id, started_at, ended_at, words_start, words_end) · derived from snapshots rather than from a counter that only goes up - export_runs(id, at, target, output_path, validator_output, state) · including the failures, which are the ones worth reading - The folder of scene files is the manuscript. Delete the database and everything but the plot grid rebuilds from the files; delete the files and the database is a list of things that no longer exist.
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 |
|---|---|---|---|
PROJECT_DIR | required | ~/Writing/novel | The folder of scene files. This is the manuscript; everything else is derived. |
INDEX_PATH | required | ~/Writing/novel/.index.db | The rebuildable index. Safe to delete at any time. |
SNAPSHOT_DIR | required | ~/Writing/novel/.snapshots | Versions before every replace. Back this up with the manuscript. |
SNAPSHOT_KEEP | required | 200 | Per scene, alongside the age rule. Neither ever removes the newest. |
SNAPSHOT_MAX_AGE_DAYS | required | 180 | The age half of the retention rule. |
AUTOSAVE_SECONDS | required | 20 | How much typing an unexpected shutdown can cost. |
MODEL_API_KEYsecret | optional | sk-...redacted | Optional rewrite of a selected passage only. The application works entirely without it. |
EXPORT_DIR | required | ~/Writing/exports | Compiled manuscripts and book files, with the validator output beside each. |
The build, in order
Files first, index second
The manuscript is a folder of readable files and the database can be thrown away.
The identifier is what everything else will hang from.
Files
src-tauri/src/scenes.rssrc/scenes/frontmatter.tsReading it back is the cheap insurance against a truncated write.
Files
src-tauri/src/atomic.rstests/crash.test.tsAn index you are afraid to delete is a second copy of the truth.
Files
src/index/rebuild.ts
done when · tick each as it passeswatch out- Keeping the manuscript inside a database with an export button means that a failed migration, or a crash during a write, leaves the whole book inside one binary file that no other program can open, and this is the failure that ends writing projects rather than merely annoying people. Put the words in plain files, verify the replacement reads back before it becomes the scene, and make the index something you can delete and rebuild on a Tuesday.
Snapshots, and a way back to Tuesday
Any scene can be restored to what it said several days ago, byte for byte.
The version you want back is the one that existed before the save.
Files
src/snapshots/take.tsBoth rules, because either alone has a bad day.
Files
src/snapshots/retain.tstests/retention.test.tsRestoring the wrong version should not be the end of it.
Files
src/snapshots/restore.tstests/restore.test.ts
done when · tick each as it passeswatch out- An undo stack that lives in memory disappears the moment the application restarts, which is exactly when a writer wants back the paragraph they cut before lunch, and an editor that cannot return it gets replaced by one that can. Snapshot to disk before every replace and on a timer, keep them under a stated retention, and put the restore in the test suite rather than in the documentation.
A plot grid that survives a reorder
Moving chapter twelve to chapter four leaves every beat where it belongs.
Position is the one property that changes constantly.
Files
src/plot/beats.tstests/reorder.test.tsDoing it by instinct in the moment gives a different answer each time.
Files
src/plot/split.tsREADME.mdA silently detached beat is worse than a missing one.
Files
src/plot/orphans.ts
done when · tick each as it passeswatch out- Attaching plot beats to a scene's position in the manuscript means the first structural edit silently invalidates the whole grid, and because it is silent nobody notices until the rewrite, by which point the grid is a picture of a book that no longer exists. Key beats on the scene identifier, decide and document the split and merge rules, and run an orphan report every time the index rebuilds.
Counting words honestly
One documented counting rule, session totals derived from snapshots, and nothing that shames.
Otherwise the rule is whatever the code happened to do.
Files
docs/word-counting.mdsrc/count.tsSo a day spent cutting reads as a day spent cutting.
Files
src/sessions.tstests/sessions.test.tsA writing tool that nags is a writing tool people avoid opening.
Files
src/goals.ts
done when · tick each as it passeswatch out- Every tool counts differently, so a manuscript reading ninety thousand in your editor and eighty seven in a submission form makes the writer distrust both numbers, and a daily total incremented as you type also counts the thousand words you deleted an hour later. Document what the counter counts, derive session figures from the difference between snapshots so a deletion shows as a deletion, and leave goals switched off by default.
An export a shop will acceptproduct builder
The book file carries the metadata its specification requires and is validated before it is written.
The specification is explicit about which fields are required.
Files
src/export/metadata.tstests/metadata.test.tsA file that exists and is rejected costs more than no file.
Files
src/export/validate.tsA lost scene in a hundred and twenty is not visible by eye.
Files
src/export/compile.tstests/roundtrip.test.ts
done when · tick each as it passeswatch out- The current EPUB accessibility specification, a recommendation dated 17 October 2024, states that all publications 'MUST include accessibility metadata in the package document that exposes their accessible properties', naming access mode, accessibility feature and accessibility hazard as required and accessibility summary and access mode sufficient as recommended. Separately the European accessibility rules have applied since 28 June 2025 and treat e-books and their reading software as a service, with an exemption for microenterprises providing services, defined as fewer than ten people and turnover or balance sheet total not above two million euro. Checked on 15 September 2026. So an export with no accessibility metadata may simply be unsellable in that market, and whether the exemption applies is a fact about the seller rather than about the file.
That is the whole plan for Dabble. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Cloud sync and mobile access.
- Collaborative editing.
- A style or grammar model of your own.
- Browser and office suite extensions.
- cloud sync, mobile access, goals, and polished manuscript organization
- cross-device sync
- large proprietary style models
- browser and office-suite extensions
- team style guides
- A read-only reading mode that renders the compiled manuscript, which is how continuity errors actually surface
- Scene status tracking through a revision pass, which is a column in the grid rather than a new screen
- An export target for a submission format with its own layout rules, built behind the same validate-then-write path
Need the files? The project pack on the verdict page hands your agent the whole brief · more writing tools.