Changelog
1.0.3 - 2026-09-19
- Added a dedicated Updates settings page with a manual update check.
- Made Outline and Progress columns resizable, persistent, and easier to scan.
- Restored mouse scrolling, sticky headings, and full-row vertical resizing in Planner.
- Added Activity annotations and reliable word attribution across Planner and Editor.
- Made Focus active/idle accounting use elapsed wall-clock time and corrected Dashboard writing-time history.
- Added dialogue percentage to Progress with support for multi-paragraph quoted dialogue.
- Improved scene naming, compendium renaming, card spacing, and Planner typography.
1.0.2 - 2026-09-11
- Improved storage folder switching and display.
0.9.12 - 2026-08-14 (beta)
The themes release. Nine themes in a 3x3 gallery, with cards large enough to show what you are picking rather than a swatch and a name. Plus the Preview typography fixes that came out of reading a real manuscript in it.
Themes
- Nine, arranged as a gallery. Dark row, light row, colored row. The cards show chrome, page and a few lines of prose, because a theme is a reading environment and a color chip does not tell you how it reads.
- Sunset becomes Vespers. The brand palette now carries the name, and it is the default.
- The old Vespers becomes Afterglow, retuned from navy to a slate hour: restrained where the brand theme is saturated.
- Dove is new, a cool light theme.
- Vespers' page is less yellow. The writing surface carried a vanilla cast strong enough to compete with the brand orange rather than sit under it. Still warm paper, not screen white.
Theme names are settled now. If a palette changes character in future it gets a new name rather than inheriting one, because a stored theme name is a promise about what a writer sees when they open the app. This release breaks that promise once, deliberately: anyone who never touched the picker had "vespers" stored, and it now means the brand palette rather than the old navy. That was a choice made while there was nobody to surprise, and it is not a choice available again.
Preview
- The drop cap sits properly. It was pushed low enough that its baseline hung below the second line instead of resting on it.
- A short opening paragraph no longer shoves the next one. The drop cap floats two lines deep, so an opening shorter than that let the float escape into the following paragraph, which then added its own indent on top of the offset and landed twice as far in as its neighbours. Found in a real manuscript; every scene in the demo book opens long enough to hide it.
- Contents has room. Off the panel edge, chapters nested under their beat, and beats in title case so the same beat does not read as two different things depending on which panel you are in.
0.9.11 - 2026-08-14 (beta)
The quiet release. 0.9.10 put the licensing machinery in place without switching a paid tier on; this one spends 48 commits making the app easier to be inside. The Editor lost a nav row, four borders, and about fifty vertical pixels, and gained the prose back. Scene status stopped being paperwork and started being derived from the writing. Sessions stopped starting themselves. And a long copy sweep took out every em-dash and every tooltip that only repeated what was already on screen.
Nothing here is a headline feature. All of it is the difference between an app you use and an app you like using.
The Editor gets out of the way (#545, #547, #552, #553, #554, #556, #558, #559, #560, #561, #562, #563)
- One nav row instead of two (#547), the status bar moved to the bottom (#554), and the panel title retired. Three separate claims on vertical space became one, which bought roughly three more lines of prose above the fold.
- Borders audit (#552, #553). Four borders that existed to organize chrome came out. Chrome does not need organizing when there is less of it.
- Sidebar reads as a table of contents (#558, #559): quieter chapters, add-scene living on scenes where it belongs, and a line-spacing cycler.
- Marks (#562): gutter avatar stacks, a sticky rail heading, and unattached notes retired.
- Text measures retuned to 500 / 640 / 780 (#572), replacing numbers that had been picked by eye.
- SPACE tokens (#556) so spacing is a vocabulary rather than a series of decisions.
Preview became a reader (#566, #569, #571)
- Renamed from Manuscript (#566). The tab was pretending to be a submission proof, and it was never going to be one.
- Continuous reading surface (#569) rather than paginated approximation. Three pagination engines were tried and rejected before accepting that the honest version of this surface is a reader.
- Comment from Preview (#571) through the Editor's own popover, so noticing something while reading does not mean navigating away to say so.
Sessions start because you said so (#575, #567, #577, #546)
- Nothing auto-starts (#575). Crossing a word threshold used to create an intention and start a timer on a five-second fuse. Now the threshold only emphasises a button that was already there. Declaring what you are about to do is a decision, not a side effect of typing.
- Focus rows read as rows (#577), and yesterday's carry-over is bounded so it cannot grow without limit.
- Starting a carried task moves it to today (#546). Picking up yesterday's intention used to leave it filed under a day that was over while the timer ran on it.
Scene status, worked out from the prose (#601, #602, #603)
- A status ladder (#617) that reads New, Drafting, Revising, Finished off the snapshots the app was already writing. Nothing new is stored to make it work.
- The writer can pin any rung (#618), and the weight says who chose it: bold means you set it, regular means Vespers is reading it. One menu entry hands it back.
- It never walks back down (#619). Clearing marks without touching the prose is tidying, and it used to drop a revised scene to Drafting, which read as the app forgetting what you had done.
Cards, Planner, Dashboard
- Cards: beats become regions and the card becomes the object (#615). Three purposeful densities instead of one card with optional decorations.
- Planner sub-tabs moved into the app chrome (#611) on the same furniture the Dashboard and Editor use, so the three stop drifting apart.
- Dashboard answers three questions and shows a year (#616) rather than being a monitoring console. Focus Insights and the Dashboard stopped duplicating each other.
- Overview counts only visible columns, and editing a cell no longer scrolls the outline to the top (#605).
Words that earn their place (#600, #612, #613, #622)
- Every em-dash that reaches a screen is gone (#600).
- "Tasks done" became "intentions completed" (#612), matching what the writer actually declared.
- Tooltips that only repeated the screen are gone (#622): the density buttons, the carry-over badge, the status cells, the per-session percentages. A tooltip earns its place by saying something the screen does not.
- Casing corrections across the Editor strip, Planner Cards, and the Dashboard activity bars.
Licensing (#543)
- License keys are Lemon Squeezy's now. The old self-signed keys ran to about 324 characters and read to buyers like a leaked private key. They were not one, but the impression was the problem. Keys are now the 36-character key Lemon Squeezy issues. Activation checks once and stores the result; every launch after is offline. Deactivating actually releases the machine, which the panel had been promising and not doing.
Also
- Sunset theme (#565), brand-forward and opt-in.
- One messaging system (#573), replacing two that disagreed.
- Scene-doc words counted with the shared counter (#608) rather than a raw whitespace split.
- Tutorial video recorder (#544).
0.9.10 — 2026-08-05 (beta)
The paid-tier release. Every piece of licensing infrastructure that will make 1.0 shippable: trial timer, Settings > License panel, feedback modal that extends the trial, Cloudflare Worker that mints Ed25519-signed license keys on Lemon Squeezy purchase, thank-you page, offline client-side verification, grandfathering for pre-1.0 installs. Purchases can flow through the whole pipeline end-to-end today (LS in test mode). Also lots of writer-facing polish across Planner, Editor, and the Dashboard.
Paid tier / licensing (#365 series: #535, #536, #537, #538, #539, #540)
- Trial machinery (#536). Ten-day trial anchored to a first-launch keychain stamp (#535); extends by 10 days on first feedback submission (one-time). Trial state, Settings > License panel with countdown + progress bar, Purchase / Send Feedback buttons, the Feedback modal with three prompts, and a TrialChip in the top nav that goes silent above 3 days remaining and red past expiry. At expiry, editing surfaces switch to read-only; reading, exports, and license entry keep working.
- Client-side license verification (#538). Ed25519 signature verification against the public key baked into the app binary at compile time. Verification is offline — once the buyer pastes, no network round-trip. Settings > License panel branches by state: Unlicensed / Licensed / Invalid / Unknown, each with its own UI. Two-click deactivate for machine transfers.
- Grandfather pre-1.0 installs (#539). Any writer whose first-
launch stamp reads
0.9.xis automatically unlocked at 1.0 first launch. Warm "Vespers is yours. Thanks for being an early user." panel replaces the trial + license flow. Pure derivation from the stamp; no separate flag to migrate. - Copy polish (#537, #540). Sentence-case across the panel + modal (no all-caps chrome). Warmer register: "As a thank you, we'll extend your trial by 10 days" instead of the transactional first draft. Friendly generic "Invalid license key" copy (technical errors go to console). Explicit green "License activated" callout on successful paste.
Server side lives at vespersapp.com (worker/) — Cloudflare Worker
handling the LS order_created webhook (HMAC-verified), signing
via Ed25519 (private key in Worker secret, public in app), storing
in D1, plus a /license thank-you page with email-lookup fallback
and a /feedback intake.
Planner (#489–494)
- Cards + Progress consistency (#490, #491, #494). Single click model across the planner (Outline, Cards, Progress). Copy sweep to match. Beat / chapter / scene rename → Outlining → Planning.
- Selection-aware shortcuts (#493). ⌘⇧I sends the currently- selected scene to Focus, not always the current scene.
- Focus row alignment (#492). Delete column reservation so Begin / Done buttons don't shift horizontally as rows change state.
Editor & marks (#514, #522, #524)
- Marks always visible (#514). Gutter glyphs + mark visuals render in both Write and Review modes. Review's job narrows to "open the right rail, hide the left sidebar." Comment marks are a dotted underline on the anchor text; standalone notes are zero-width markers with text in the gutter popover + rail card. One unified popover for create + edit (was two, subtly different styles).
- Shortcut strip cleanup (#523, #524). Snapshot dropped from the shortcut strip; mark navigation added when Review is on. Editor chrome trimmed to match Planner's cleaner style.
Compendium (#515, #522)
- Description input retired (#515). "Short description (optional)" was noise in the sidebar. Removed the input surfaces in EditorFileManager and EditorWorkspace, plus the tagline subtitle under each entry in the sidebar. Model + parse + serialize preserved so existing entries round-trip cleanly.
- Snapshot header (#522). Compendium snapshots render name + tagline as a proper header above the frozen prose (was rendering the YAML frontmatter as a broken-looking rule).
Dashboard (#528, #532, #533)
- Contribution heatmap contrast (#528). Bumped low-end alphas (0.18 → 0.32 for words, 0.20 → 0.34 for pomodoros) so light-writing days actually show against the empty-cell tint.
- Readability metric swap (#532). Automated Readability Index
replaces Flesch-Kincaid as the single readability grade. Character-
based (chars/word) so the number no longer depends on the syllable
heuristic. Same narration-only scope, same grade-level bands.
StatCard
(?)glyph +cursor: helpon any card with a tooltip. - Sentence-length integrity check (#533). Real-corpus test reads the full text of Treasure Island (checked-in .docx) and asserts the histogram's bucketing matches the words in the sentences it claims to be counting. Uncovered + fixed two bugs in splitSentences (quote tracking + abbreviation guard) and added an orphan-attribution filter.
Copy & UX polish (#516, #519, #520, #530, #537, #540)
- Capitalization passes for tooltips, confirm labels, shortcut strips, and Planner sub-tab footers.
- Em-dash retired from the delete-scene arm confirm.
Under the hood
- First-launch keychain stamp (#535). Records
{version, at}in the OS keychain on first-ever launch. Foundation for grandfathering and trial math. Survivesrm -rf ~/.config/vespers. - Dependency: added
ed25519-dalek(verify-only),base64,keyring,chronoon the Rust side.
0.9.9 — 2026-07-29 (beta)
The review-mode groundwork release. Marks now behave cleanly under real editorial workflows: imports from Word land without swallowed resolves, colored marks preserve their palette, comments stay one line inline (full text lives in the rail and popover), and the right rail is opt-in per-scene so Write reads as prose again. Under the hood, a Playwright-driven screenshot pipeline seeded with four weeks of realistic writing history now feeds vespersapp.com/docs. Every theme, every panel, no more staged screenshots that drift from the UI.
Editor & marks (#427, #434, #435, #438, #447, #448, #449, #450, #451, #452, #453, #455)
- One-line comment callouts (#455). Inline note previews truncate at the first newline (plus a 120-char cap) with an ellipsis. Long or multi-line comments live in the rail card (click to expand) and the ⌘⇧M popover; the inline callout is a peek, not the whole thread. CSS enforces single-line rendering too so the box can't grow past one line even if the preview is very long.
- Right rail is scene-only + opt-in (#453). The TOC + in-scene marks rail hides by default; a thin chevron pinned to the writing area's top-right toggles it, persisted per writer. Write no longer feels like a triage console the moment a mark exists (#451).
- Softer spotlight + calmer rail copy (#452). "IN THIS SCENE" and "open marks across" replace the noisier "DOC MARKS" / "REMAINING ACROSS" phrasing. Spotlight halo alpha dropped so the highlighted mark reads as attention, not alarm.
- Two-clean click model on marks (#450). Clicking on highlighted or commented prose places the caret (writers can edit inside a marked passage without opening a modal); clicking the note callout opens the popover. Doc Marks rail cards get a pill around the quoted text with the attribution ("inserted by Cara") on a line below, in the pattern of real editorial marginalia.
- Marks survive .docx imports (#447, #448, #449). Fixed three
resolve failures uncovered by real .docx round-trips: colored
marks (color-prefix wasn't stripped from the enumeration), Cara-
imported comments (whitespace hoisting missing in
to-critic.tsleft a leading space the browser trimmed but the enumerator didn't), and a diagnosticconsole.warnfor future mismatches. - Mark color palette + preservation (#400 / #438). Word's darkYellow/darkGreen etc. normalize back to the base color; a curated 7-swatch palette in the bubble toolbar lets writers pick a color on their own marks; the color survives the .md round trip.
- Editor shortcuts footer pinned (#427 / #434, #435). Fixed the case where the footer was floating mid-panel after long scenes scrolled the layout. Flex chain sizes it now. Regression tests lock the behavior.
Planner columns (#413, #423, #424, #425, #426)
- Default column set overhauled (#413 / #423). Purpose, Setting, Conflict, and Theme replaced the older preset system. Drop preset swapping; writers pick columns individually and the choice sticks.
- Column order matches how writers think (#425, #426). Purpose and Setting visible by default; Conflict as the third visible column; Theme fourth. Existing projects hydrate to the new defaults on load (#424).
Scene breaks (#428, #430)
- Auto-detect
* * *and***on Enter (#428). Typing either at the start of a line inserts a scene-break node instead of leaving raw punctuation in the manuscript. The centered dinkus renders inline in the editor now (#430), so writers see the same visual mark they'll ship without toggling to Manuscript view to verify.
Themes + contrast (#441, #442)
- All theme × surface pairs pass WCAG AA (#441). 72 vitest assertions lock every theme's text and UI contrast (4.5:1 / 3:1) so palette drift fails CI, not review.
- Three new themes: mocha (was "leather"), sage (was "forest"), and nautical (new). Screenshot suite covers all five (#442).
New-project wizard + copy (#415, #416, #418, #419, #420, #421, #422, #429, #432, #436, #437)
- Cancel affordance on the wizard name screen (#416 / #422). Writers who open the wizard by accident can back out cleanly.
- Two copy passes across the new-project flow (#420, #421) plus a final consistency sweep (#437) and first-time-user copy update (#436). Voice pulled toward the Vespers house style: dry, language-nerdy, warm at the entry points.
- Writing style + editorial checklist docs (#432) added under
docs/to keep future copy grounded.
Screenshot pipeline (#411, #412, #415, #417, #431, #439, #440, #442, #443, #444, #445, #446)
- Playwright-driven, theme-aware screenshot infra (#411, #412).
Seeded fixture spins up a realistic project (chapters, scenes,
compendium, marks) and renders panel-only crops in each of the
five themes.
VESPERS_SHOTS=1gates the run; output feeds the docs site. - Four weeks of realistic writing history (#431). Fixture includes daily word counts, focus sessions, and snapshot rollups so Dashboard + Focus Insights render with lived-in data instead of empty states.
- Editor + Focus + Dashboard coverage (#439, #440, #443, #444, #445, #446). Focus with today's intentions, Editor in Write and Manuscript modes, Dashboard capturing the full Contributions heatmap in a tall viewport.
Fixes (#404, #405, #406, #407, #408, #409, #410)
- Open-scene always lands the writer in Write mode (#406 / #407). No more accidental Manuscript-view opens when clicking a scene from the sidebar or search.
- Add beat / chapter / scene ABOVE in the Planner (#405 / #408). Right-click menu now offers "above" alongside "below" so writers can insert without dragging.
- Empty-chapter drop zone + planner legend dedupe (#404 / #409 / #410). Dragging a scene into an empty chapter works reliably; the legend no longer double-renders on resize.
0.9.8 — 2026-07-23 (beta)
The .docx round-trip release. Writers can now bring a manuscript in from Word (tracked changes, comments, colors, and all) and export a Shunn-compliant .docx that agents and editors expect to receive. Plus a small pile of editor polish that came out of dogfooding the import path against real material.
Import from Word (fixes #383, #391)
- .docx importer (#390). Preserves every editorial mark:
tracked insertions/deletions map to CriticMarkup, comment
threads collapse into single anchored notes, Word highlight
colors survive as
[color]prefixes. Chapters come from H1s, scenes from# # #separators, all landing under an "Import" beat. Fallback chapter title uses the .docx filename when the document has no headings. - Books as beats (#393). Multi-book documents (War and Peace shape: H1 books containing H2 chapters) import as one beat per book instead of flattening into a single wall of chapters. Auto- detects the H1/H2 hierarchy; single-level documents still land as a flat Import beat.
- Import perf at scale (#391). Memoized
ManuscriptPanelrender + killed a per-scene autosave storm that was blocking the UI during large imports. Treasure Island-sized documents (~120 scenes) now import without stutter. - Gutenberg fixture generator (#392, #399). Dev tooling that
turns any Project Gutenberg URL into a .docx stress test.
Handles PART headers, bare-Roman-numeral chapters (
I/IIcentered above titles), and CRLF line endings out of the box.
Manuscript export to Shunn spec (#394, #398, #399)
- 37-test spec suite locks the whole export shape (#394).
Every section of
docs/export-specifications.md(page size, margins, font, spacing, title-page layout, chapter openers, scene breaks, end matter) is asserted against a real .docx round-tripped through fflate + DOMParser. Regressions fail CI loud rather than showing up in a submission draft. - ALL CAPS discipline (#394). Book title, chapter openers, and THE END all render in ALL CAPS at the export layer; writers can keep their working titles cased however they like.
- Bulletproof mark stripping (#394). CriticMarkup sigils,
[color]prefixes, and raw<mark>/<span>HTML from any round-trip gap are all stripped before the exporter emits runs. Regex order matters (solo highlights first with negative lookahead, then paired) and there's HTML fallback stripping to catch anything upstream missed. - Contact block on the title page (#398). Full name, two-line
address, phone, and email single-spaced in the top-left corner;
word count top-right. Manuscript info moved from "story info"
and split into first/last name so the export filename can use
the Shunn
Lastname_title.docxconvention (#395). Email gets forced to lowercase on the way out. - Scene breaks and end matter (#398). Scene breaks are
centered
* * *; THE END is# THE END #. Both match #396 and #397 exactly. - Every body paragraph carries its own double-spacing (#394).
Word and Google Docs both silently drop
docDefaultsdouble-spacing on load; puttingspacing: DOUBLE_SPACINGdirectly on each paragraph makes it portable.
Editor polish (#389, #402)
- Comments tab on the editor rail (#389). Sits alongside Headings so the writer can walk every comment in the current scene without opening a modal.
- Marks tab populates immediately after import (#402). Was empty until the writer clicked each imported scene one by one; now the sidebar reflects every imported mark the moment the import completes.
- Tighter block-mode paragraph gap (#402). Dialogue exchanges no longer feel airy; paragraphs still visually separate.
- Manuscript drafting style (#402). New editor pref for writers who like the drafted page to look like the printed page. Adds a 2em first-line indent and drops the gap; first paragraph after a heading or scene break stays flush. Toggle in Settings → Editor.
- OutlineGrid cell caret (#402). Clicking inside an open cell edit now places the caret where you click instead of exiting edit mode. Drag-select and triple-click work too.
0.9.7 — 2026-07-20 (beta)
State-cleanup + outline data-entry release. Fixes a cluster of "previous project's state leaked into my new project" bugs and tightens the outline grid for writers who spend real time filling in Purpose / POV / Theme across many scenes.
State scoping (fixes #375, #376, #378, #382, #383)
- Hard reset on new-project create (#385). Timer, isBreak,
isPaused, activeTaskId, engagement counters, flowChain,
currentPomodoroWords, notices — all cleared before flipping
activeProject. If a session was mid-flight, the in-flight
pomodoro row closes as
completed=0so the old project's history stays honest and the new project's stays clean. Session mode re-reads localStorage so the wizard's step-3 pick wins. Landing tab set to Planner > Outline (writers reach for beats first, not an empty scene). countTodayCompletedPomodorosscoped by project (#385). The dot tally next to "Today's intentions" no longer aggregates across every project; each project shows only its own count. Fixes both the create case and the switch-between-existing case.- Sub-tab preferences per-project (#386). Planner sub-tab (Outline / Cards / Progress) and Editor sidebar tab (Scenes / Compendium / Snapshots / Marks) now key their localStorage by project name. A fresh project falls to the default (Outline / Scenes) instead of inheriting whatever the previous project was viewing. Existing projects keep their own preference.
Outline data entry (fixes #380, #381)
- Enter commits + moves down on every cell type (#387). Spreadsheet convention (Sheets / Excel / Numbers / Notion / Airtable). Was: metadata cells inserted a newline on Enter because they render as textarea, forcing a Tab-to-commit-then- sideways-then-wrap-down rhythm across a row of scenes.
- Alt/Option+Enter reserves the newline escape in metadata cells for the rare multi-line Purpose (matches Excel's Alt+Enter convention). Name cells stay single-line per schema.
- ~three rows of bottom padding on the grid's scroll container (#387). The last row no longer sits flush against the border when the writer scrolls to the bottom to edit it.
CI
- Release workflow's tag trigger disabled (#374). Every tag
push (v0.9.5, v0.9.6) was firing a red Release run because the
runner has no Developer ID cert. Dropped the tag trigger; kept
workflow_dispatchfor manual runs. Tag pushes are now clean. Header comments the four-step recipe to re-enable when the .p12 cert lands as a repo secret.
0.9.6 — 2026-07-19 (beta)
Focus polish + Planner sub-tab parity. Fixes the day-level session tally, silences ∞ open on relaunch, tightens the timer chrome, adds "Add to Focus" everywhere it was missing, and stacks Cards chapters vertically on standard/large so wide beats no longer force a scroll. Companion 0.9.5 test-drive feedback drove most of the changes.
Focus
- Walk-away check reads the tail, not the whole session (#367). Old logic ended the chain whenever total idle within a block hit 5 minutes — so a writer who paused for 6 min mid-session then worked to the boundary got treated the same as one who walked away and never came back. New rule: only the last N minutes before the boundary matter. Mid-session pauses stay honest in the DB's active/idle split but don't affect chain-continue.
- Sandbox warp buttons split into +60s active / +60s idle (#368). Icon-only during a run so they don't widen the controls row. Five idle clicks now marches the walk-away tail past the threshold, so the test drive doesn't need 30 min per iteration.
- ∞ open never breaks — including after resume (#368). Boundary effect used to fall through to the 25/5 break path when `flowChain` was null; `acceptResumeOffer` restores state without seeding `flowChain`, so a resumed ∞ open session would drop into a 5-min break at its next boundary. Now the effect also checks `sessionMode` and ends the session quietly instead.
- ∞ open on relaunch: no resume pill (#369). Silent-by-contract now holds through app restart. Orphan gets closed as partial with ended_at at the last-heartbeat cap; row keeps its active/idle numbers so the dashboard still shows the elapsed time. Other modes get the resume pill as before.
- block → session in writer-facing copy (#368). "Block" evoked the wrong idiom. Mode-picker tooltips, boundary toast, chain-end notice, end-after-this button, wizard body copy all rewritten.
- Timer chrome pass (#368):
- Mode picker stays visible during a run (disabled + muted, was hidden), so the mode reads the same at rest and in flight.
- Intention pill moved below the timer + immediately above the controls — shorter mouse trip from pause/continue back to "jump to the file." " · paused" suffix dropped.
- Arrow prefix on the intention pill swapped for the same `FileText` glyph the Outliner uses.
- "End after this" moved off the retired chain strip into the controls row as a small pill. Flow-only — ∞ open's silent contract precludes it; 25/5 has no chain to end.
- Focus dots are a day tally, not a per-instance counter (#370). Fetches from the DB on mount + on each pomodoro completion so two morning sessions still show as two dots when the writer comes back in the evening. Day boundary follows local time.
Planner
- Add to Focus on Cards + Progress (#371). Right-click a scene card or a Progress row → same one-item menu the Grid + Editor sidebar have had since #314. Progress also gains a `FileText` glyph next to each scene name — visual grammar match with the Grid.
- Cards detail modal: "Add to Focus" pill in the header (#371). A mouse-only writer clicks a card, then clicks the pill, no right-click needed.
- Cards chapters stack vertically on standard + large (#371). Wide beats used to force horizontal scroll; the vertical stack reads as clean "chapter → row of scenes" sections and nothing hides off-screen. Compact stays horizontal — density is the whole point of that size.
Copy
- "Add to Focus" is the label everywhere (#372, closes #361). Was a three-way split: "Add scene to Focus" on scene surfaces, "Send intention to Focus" on compendium menus + the new-entry form. Consolidated so writers build one habit, not three.
0.9.5 — 2026-07-18 (beta)
The onboarding-polish release. 0.9.4 landed the first-launch flow; this one iterates on it after wife-and-writer test drives surfaced where it snagged. Three static hint cards collapse into one action-responsive walkthrough card that follows the writer across panels. A persistent formatting toolbar lives in the Editor. The auto-track pill becomes a countdown-with-cancel. Silent mode really is silent. The Editor's chrome-hide mode is renamed to reduce a name collision with the Focus tab. Plus outline usability, safer default template loading, and a scattering of fixes.
Onboarding
- Action-responsive walkthrough card (#355, #357) replaces
the three per-panel hint cards from 0.9.4. One floating card
bottom-left, four steps: add a scene and title, provide a
purpose, open the scene, add a mark or type. Each step lists
the mouse action and the keyboard shortcut; no reasoning
copy — writers wanted a checklist, not a lecture. Detection is
observational: App watches outline / activeScene / sceneBody
and advances the step index as each condition is met. Persists
the step + dismissed marker across relaunches so a partway-
through writer picks up where they left off. Settings > Project
reset hints brings it back at step 1. Bottom-left placement so it doesn't fight the auto-track countdown pill + toasts at bottom-right. Deleted OutlineHintCard, FocusHintCard, EditorHintCard, and their shared HintCard shell.
- Wizard step 3: focus-session default (#347). Writers now
pick 25/5, 30 flow, or ∞ open at project-create time. Writes
the same
vespers.sessionModekey the Focus panel reads, so the first session starts in the shape they picked. - Fix: welcome flow was silently producing beat-less
outlines (#356). Two root causes stacked:
list_templates/load_templateassumed the templates directory already existed. Seeding lives inensure_dirs(), called bydb_url(); whichever bootstrap effect fires first decided whether the wizard saw any pills. On a profile whose root didn't exist yet (this session: showcase at~/Vespers/_showcase), the wizard won the race and the writer saw no options. Both commands now callensure_dirs()at the top; idempotent, doesn't clobber writer edits.OutlineGridreturned "no rows yet, press ⌘⇧B" wheneverrows.length === 0, including when the outline had beats but a stale level-filter (localStorage) was hiding them. Worse, the pills that could unhide them lived AFTER the early return. New empty state renders the pills either way, and when the outline has content shows "filters are hiding every row. toggle a level above (or show all)."
Editor
- Persistent formatting toolbar (#354, closes #332). Bold, italic, headings 1–3, bullet + ordered lists, blockquote, undo, redo — always visible above the writing surface, ProseMirror- wired so the buttons echo current formatting. Surface-aware: scenes get a Shunn-compatible subset; compendium + docs get the full toolbar including headings. Sits outside the CSS grid so it doesn't compete with the optional TOC rail for column width.
- Headings drop entirely on Shunn export (#354). H1–H3 in a scene were previously de-marked-and-kept as body paragraphs; now they're skipped whole-block so a writer can use them as scaffolding without any of the text sneaking into the manuscript.
- Sidebar auto-expands the active scene's chapter + beat (#352). Opening a scene from Planner / Quick Open / walkthrough now unfolds the enclosing path so the sidebar highlight lands on-screen. No more silently-collapsed active scene.
- Distraction free replaces "focus mode" in writer-facing
copy (#342, #351). The tab is Focus; the Editor's chrome-hide
mode is "distraction free". Code identifiers stay
focusMode.
Planner + Outline
- Outline usability pass (#348, closes multi-issue). Beats
seed a "New chapter" placeholder so a first-time writer isn't
stuck at right-click > add chapter > right-click > add scene.
The chapter-level legend on the Outline sub-tab renames from
"Beat / Chapter / Scene" to "Levels" (the pills already say
the words). Scene rows gain a document glyph in the indent
slot; clicking it opens the scene.
⌘Oon a selected scene row does the same. Scene indent bumped fromINDENT_STEP*2toINDENT_STEP*3and WBS column widened from 44 to 48 so three-level codes (3.4.7) don't crowd the left border.
Focus
- Auto-track pill: 5-second countdown to auto-start with
cancel (#353). Writing in a scene for 30s no longer opens a
yes/no offer; instead a pill slides into bottom-right with a
visible countdown, a cancel X, and starts the tracked session
automatically when the count hits zero. Silent mode
(
∞ open) skips the pill entirely and starts the session immediately (#349) — the whole point of the mode is not being interrupted, and a 5-second pill was still an interruption. Cancel now also clears the per-session active/idle accumulators (#350) so the next session doesn't inherit half a stopped one.
Fixes
- Cancel clears per-session state (#350). Cancelling a running session mid-block used to leave active-seconds, idle-seconds, and the flow-mode chain populated for the next session's first tick.
0.9.4 — 2026-07-18 (beta)
The onboarding release. First-launch flow reads end-to-end for a writer who's never seen Vespers before: a welcome modal picks the door, a two-screen wizard makes the project, and dismissable hint cards on Planner, Focus, and Editor hand over the four verbs each surface expects. Plus a real safety net under project delete, a click-back affordance on the Focus intention pill, a font sweep across every muted italic helper, and the usual scattering of copy polish.
First-launch
- Welcome modal. Renders once on first launch until dismissed. Single door for now (Start a new project) with a warmer voice than Settings; footer text sits at 13px, no italic (was 11px italic).
- Multi-screen new-project wizard. Replaces the cramped inline form in Settings > Project. Screen 1 is the project name; Screen 2 is a pill picker for every bundled beat structure (Blank, Three Act, Seven Point, Hero's Journey, 15-Beat Dramatic Structure) with a live preview of each pattern's beats + notes underneath. Preloads on entry so pill labels are the real names ("Hero's Journey", not "heros journey"). Modal anchors near the top so the frame stays steady while the preview reflows. On create, lands the writer in Planner > Outline instead of an empty Editor.
- Getting-started hint cards on Planner, Focus, and Editor.
Table (Planner) or descriptive sections (Focus, Editor). Each
card locks with an X in the corner; localStorage marker
persists per install. Shared HintCard shell handles pagination
("Card N of M") + a global reset signal so Settings > Project
reset hints brings every card back live without a tab-switch.
- Sample-project door in the welcome modal is deferred to a follow-up (needs a real WIP project seed).
Focus
- Intention pill above the timer is now a link (#330). Click
to jump back to the surface the task was created against
(scene, compendium entry, doc, outline). Underlined, accent-
colored, 13px.
activity: otherintentions stay as a plain span so a stray click can't fire a no-op nav. - Cleanup:
beginPomodoroOnTasknow shares its surface-nav path with the new link click via anavigateToTaskSurface(task)helper. No behavior change for existing session-start callers.
Planner + Editor + Focus
- "Send intention to Focus" → "Add scene to Focus" on scene right-click menus in the Planner grid and the Editor sidebar (#336). "Intention" was Vespers vocabulary that made writers guess what noun was being sent; the object is a scene, so the verb names it. Compendium right-clicks kept the old label for now — same rename deserves a follow-up scoped to that surface.
Safer project delete (#333)
- Confirmation modal replaces the two-click armed delete on
Settings > Project. Two backup exits both remove the project
from Vespers when done:
- Archive to Desktop + delete —
fs::renameto~/Desktop/vespers-<name>-<YYYYMMDD-HHMMSS>/. Move is the delete; DB rows stay so the writer can restore by moving the folder back intoprojects/<name>/. - Export as .docx + delete — writes the Shunn-formatted manuscript via the existing export path, then cascades into hard-delete. Cancelling the save dialog skips the delete so the writer isn't left with nothing.
- Archive to Desktop + delete —
- Delete permanently stays available as a third option, gated behind a yes/no inside the modal.
- Copy: warning shortened to "Delete permanently removes the project folder from disk." All three buttons labeled with what they do; same minHeight / left alignment so the choice reads as one stack.
Copy hygiene
- Font sweep (#331): 58 style objects across 21 files carrying
the WCAG-unfriendly triple (
fontSize: 10–12+color: muted+fontStyle: italic) bumped to 13px, italic removed. Muted color preserved. 5 empty-state placeholders (Dashboard, Outline, Progress, Outline empty view, Activity feed) also had italic stripped even though they inherit body size. - Em-dash purge across every writer-visible surface touched on
this branch: welcome modal, quotes, tutorial (retired), memory
bodies.
quotes.tsauthor-title separators swapped to commas; the two in-quote em-dashes (Faulkner, Dickinson) also stripped for the "no em-dashes" rule to hold globally. - "Focus session", not "pomodoro" in writer-facing copy;
code identifiers stay
pomodoro.
Fixes + smaller polish
- Welcome modal's flash-then-vanish bug on first launch (Rust
auto-creates a Default project so the
projects.length === 0gate flipped false a beat after mount). - Playwright fixture bypasses the welcome-modal marker so specs don't get intercepted.
- Rust: new
archive_projectandopen_project_foldercommands. - Settings > Project > reset hints button (currently universal; handy while onboarding is still landing).
0.9.3 — 2026-07-16 (beta)
The Focus tab redesign. Intentions become the load-bearing noun, sessions become a per-session choice (Pom+break / Flow / Open-ended), and every scene / compendium entry now carries a foreign key back to its surface so a fresh intention navigates cleanly on the first session. Plus a batch of copy + measurement polish across Dashboard and Manuscript so the numbers finally match the stories they tell.
Focus redesign — intentions, three modes
- Composer stripped down. Estimate, activity picker, flow-mode
toggle, and the "smaller tasks" nudge all retired. The composer
is now a text input + Send button, always writing
activity: other. Placeholder:an intention (buy notebook, email agent, reread beat 3…). - Right-click Send intention to Focus on scenes and compendium entries in the Planner Grid + Editor sidebar. Adds the surface as an intention with its ref stored on the task, so clicking begin later navigates back to it without needing a prior session.
- ⌘⇧I — silently queues the current surface as an intention
from any tab. Doesn't navigate. Shows a brief "Sent to Focus:
" notice. - Three session modes, chosen at session start via a pill picker
on the timer widget:
- Pom+break — classical 25/5 with chime + break
- Flow — 30-min blocks chained continuously with boundary toast
- Open-ended — 30-min blocks chained silently (no toast, no chime, no notification — pure "record my time, don't tell me about it") Mode locks per session; last-used mode sticks in localStorage.
- Compendium new-entry inline form — click
+on a kind section, get a title + optional description + Send-intention-to- Focus checkbox. Perfect for jotting placeholder characters or locations that queue directly into today's intentions. - Cross-session navigation fix — auto-track pill + ⌘⇧P now also save the surface ref on the task, so a task started yesterday navigates you back to the right scene today.
- Cursor no longer jumps when starting an in-place session (⌘⇧Y, auto-track accept, task-row begin on the current surface).
Auto-track toast: bigger, centered, keyboard-friendly
- Repositioned from bottom-right corner to center-top over the editor. In peripheral vision without breaking flow.
- Bumped from
fontSize: 12to14, stronger box-shadow. - ⌘⇧Y accepts, ⌘⇧N dismisses. Prominent
⌘⇧Ychip on the pill so keyboard-first writers see the affordance at a glance.
Words, measured honestly
- Contributions "Total words" → "Words added". The card measures cumulative typing activity across the visible window; it does not net out deletions. Renaming makes the semantics honest.
- Dashboard: Manuscript total — italic under-caption to the
Writing Progress widget.
Manuscript: N words= live sum of scene bodies, answering the separate question "how big is my book right now?". - Editor → Manuscript header — adds
N wordsinline in the stats strip (7 chapters · 5 with prose · 18 words). Computed from the assembled bodies (archived scenes excluded). - Manuscript stats row drops the "N empty" chip —
N chapters · M with proseconveys the same information without spelling out the delta.
Copy polish
- Focus Insights → "By Task Type" drops the "newest on the right" subtitle (day-of-month labels below carry the same signal).
- Inspirational quotes: em-dash before the author swapped for a
fullwidth wave tilde (
~). Softer typography. - SceneDetail modal:
☐ FINALrides on the title label row instead of taking a full vertical strip for one binary toggle.
Under the hood
- Migration 010 —
tasks.scene_id / compendium_kind / compendium_slugcolumns for surface refs. - Migration 011 —
pomodoros.modecolumn (pom_break | flow | open_ended; legacy rows backfilled to pom_break). assembleManuscriptcomputes total words in one pass.- Session mode persists to
localStorage["vespers.sessionMode"]. - Cheat sheet updated with ⌘⇧I, ⌘⇧Y, ⌘⇧N.
0.9.2 — 2026-07-15 (beta)
The rename release, plus a storage-safety fix and app-wide copy polish. Same features under different words: "pomodoro" becomes "focus session" and "Outliner" becomes "Planner". Shortcuts unchanged; only the vocabulary moved.
Renames
- Pomodoro → focus session across every user-facing string. DB schema, IPC handlers, and activity keys keep their internal names; writers see "focus session" everywhere.
- Outliner → Planner in the top nav. The sub-tab formerly called "Grid" is now "Outline" — names the artifact you're making, not the pixels holding it.
- Focus & Tasks → Focus. Matches the other single-noun tabs.
Top nav reorder
- New order: Focus · Editor · Planner · Dashboard (
⌘1..4). Walks the writer's actual day: daily launcher, daily typing, weekly structure, monthly reflection. - Default active tab flips from Dashboard to Focus so cold-start lands on today's intentions.
Storage safety
root_pathself-heals. If a writer sets Vespers at.../CloudDocs/projects(a folder that already contains projects directly), Vespers used to silently double-nest into.../CloudDocs/projects/projects/and the project list looked empty. The trailing/projectssegment now strips on both read and write.- Settings shows the effective projects path directly under the root, so writers can verify where their data actually lives without opening Finder.
- 16 new Rust unit tests lock every edge case (nested
/projects/projects, case sensitivity, root-collapse guard, idempotency).
Settings consolidation
- Project, Export, and Storage sidebar tabs folded into one Project panel with three stacked sub-sections. One less trip through the sidebar to reach "download my manuscript".
Copy polish
- Multi-sentence prose across empty states, help hints, and description text is now sentence-cased. Labels + tooltips stay lowercase (house style for micro-copy).
- Em-dash-then-clause pattern ("no X yet — do Y") swapped for period-then-clause where it read as a run-on.
- Editor empty-state hint no longer mentions "notes" — there is no notes surface.
- Focus Insights header trimmed of two redundant subtitle lines.
Under the hood
- Storage IPC exposes
projects_pathfor Settings display. - e2e smoke locator anchored so
/^focus$/idoesn't collide with the Focus Insights drawer trigger.
0.9.1 — 2026-07-15 (beta)
Post-launch UX polish, mostly around the Outliner. The Grid becomes a
proper tree-grid the writer can plan straight into, the Editor gets a
sidebar-hide shortcut and instant sub-tab switching, and the top-level
tabs pick up ⌘1..4.
Outliner Grid — now the structural surface
- Inline expand/collapse chevrons on beats + chapters; scenes align under their parent chapter's name. Collapse state persists per node.
- Keyboard-first row insert:
⌘⏎child,⌘⇧⏎sibling directly below,⌘⇧Bnew beat. Works from edit mode (commits the in-flight rename onto the base outline before the insert lands). ⌘⇧↑ / ⌘⇧↓move the current row within its parent.⌘⇧← / ⌘⇧→collapse / expand the current row (Finder / VS Code convention).⌘⌫two-step delete. Rows whose descendants carry prose are blocked with a reason; metadata-only rows get a "click to confirm" swap.Tabfrom the last editable column wraps to the next row's Name — standard spreadsheet behavior. Speeds up filling a row of metadata across scenes.- Right-click menu with the same actions plus Rename / Move up-down / Collapse-Expand.
- Prose dot on scene rows that have
.mdbody content. - Structure sub-tab retired — Grid absorbed its editing role.
Editor
⌘\hides the sidebar (Write mode's scenes/marks/compendium + the Manuscript TOC). Lighter than focus mode: nav + panel-title stay.- Manuscript view stays mounted across Write ↔ Manuscript flips — instant swap, no re-fetch flash, scroll position preserved.
- Sidebar tab strip (Scenes / Marks / Compendium / Snapshots) stays pinned as the tree scrolls beneath it.
- Selection bubble toolbar for editorial marks (strike, highlight, comment) shows above any non-empty selection.
- Comment glyph on the bubble matches the standalone-note post-it SVG (was curly quotes).
- Paired-comment note text bumped to WCAG AA on every theme; long notes render as one dashed callout instead of stacking per-line.
Focus
- Right-click on Focus task rows retired — same actions as the row buttons, just noise.
- Guard against duplicate auto-tracked tasks (same text + same activity in today's open list → reuse the existing task).
⌘⇧Pon the Outliner tab attributes to "Outlining" instead of a stale scene name from a prior surface. Compendium tasks named"Characters - alice"(was"characters: alice").
Navigation
⌘1..4— jump to Dashboard / Focus / Outliner / Editor. Sub-tabs stay mouse-driven (⌘⇧3/4are macOS screenshot shortcuts).- Auto-created scene tasks: dash between WBS and title
(
"3.1.2 - Miss Bartlett's map").
UI polish
- "Snapshot" in place of "Revision" across the UI (menus, tooltips, labels, shortcuts panel).
- Cheat sheet trims self-evident rows (Esc-to-close footer, find-bar Enter/Shift+Enter/Esc, "right-click for more" hint).
- Editor sub-panels opt out of the panel fade-in animation — Write ↔ Manuscript swaps are instant instead of replaying a slide+fade every click.
- Grid footer trailing hint replaced with a pointer to the cheat
sheet (
⌘/ show all shortcuts).
Under the hood
- Save the Cat demo seed loses its
1. …15.beat prefixes (WBS numbers them). blank.yamltemplate beat named "New beat" (was "Beat 1").
0.9.0 — 2026-07-12 (beta)
First public download. Not a promise of API stability; consider it a public beta while the app gets shaken out on real writers' machines.
The full development history since project start is in the git log + merged pull requests. Highlights of the shape at 0.9.0:
Writing
- Editor with CriticMarkup-based revision marks (strikes, highlights, paired comments, standalone notes)
- Persistent focus ring on
⌘⇧] / ⌘⇧[navigation; next⌘⇧Mopens the focused mark's popover - Sidebar Marks tab shows a project-wide outline of every remaining mark, grouped by scene / compendium entry
- Native macOS spell check (enabled by right-click → Spelling and Grammar → Check Spelling While Typing)
Structure
- Outliner tab with four sub-tabs: Structure (compact tree with drag-and-drop reorder + Delete-key guard), Grid, Cards (compact/standard/large sizings), Progress
- Scenes and chapters addable + renameable from both the Structure sub-tab and the Editor sidebar's scene tree
Focus
- Pomodoro timer with pomodoro-per-task attribution
⌘⇧Pstarts a pomodoro on the current surface with a smart-named auto-derived task- "Pomodoro insights" flyout drawer with engagement %, by-task-type stacked-bar timeline (30 days, day-of-month axis), contributions grid
Dashboard
- Words-per-day + Writing progress widgets with 30-day sparklines
- Prose signals + Contributions heatmap
- Activity history feed with week + month rollup cards
Under the hood
- Tauri v2 + React 19 + TipTap
- SQLite for pomodoros / tasks / activity
- YAML outline + markdown scene files on disk (fully browsable without the app)
- Playwright e2e infrastructure with mocked Tauri IPC; 7 e2e specs + 956 unit tests