Skip to content

TomeStack 0.4.0

Choose a tag to compare

@github-actions github-actions released this 02 Oct 22:22
· 182 commits to main since this release
10eef25

The first release published on GitHub, with a downloadable installer. Version 0.4.0 comes after the 0.3.1 test installers that were built locally but never published (ADR-008 "Versioning"). It brings everything built since 0.3.0, listed below. How far each part is proven:

  • Checked on test data only, not in real play yet: M2.1 (data safety), M2.2 (the Fighter), M5 (the homebrew studio) and M6 (sharing, extensions, VTT export).
  • M3, playing a real character end to end: the engineering is done, but the gate is not met.
  • M4, reading a PDF and proposing rules: still experimental.

Unsigned: Windows shows "Windows protected your PC" the first time you run TomeStack.App-win-Setup.exe. Choose More info, then Run anyway. Some workplace PCs, and Windows 11 with Smart App Control on, block unsigned apps entirely.

Updating: TomeStack never checks for updates and makes no network calls. To update, download the newer Setup.exe and run it. Your data folder (%LOCALAPPDATA%\TomeStack) is kept and is backed up before any database upgrade.

Added

  • Download TomeStack from GitHub (roadmap T5):

    • Releases now come as a downloadable installer on the project's Releases page, built and checked automatically from a version tag.
    • The installed folder now also has THIRD-PARTY-NOTICES-Velopack.md, the licenses of the code inside the installer and updater.
    • The installer components are updated to Velopack 1.2.161.
    • ATTRIBUTION.md now has the terms for two Microsoft Windows SDK files that TomeStack uses to read text from scanned PDFs. By installing TomeStack you agree to those terms for those two files.
  • M6 exit gate checked on fixtures (M6 slice 6): a source pack, a campaign pack and a full backup with an extension each come back as they were in a fresh TomeStack data folder, except that shared sources are marked as received and an extension comes back turned off until you grant it again. Restoring on a second computer has not been tried yet.

  • Guides for homebrew authors (M6 slice 5; its extension changes approved by the owner 2026-09-30): docs/authoring/ explains how to write a class in the Homebrew studio, share your homebrew as a source pack, and write an extension, with a compatibility table. Every example in them is tested by following it as written. An extension's export is now refused if it leaves out a license notice, and extension files made with Windows PowerShell's Compress-Archive now install.

  • Export a character for Foundry VTT, or as a sheet file (M6 slice 4, ADR-012): "Export for a virtual tabletop" on the sheet saves a file you import into Foundry VTT (dnd5e system 6.0.5 on Foundry 14; Experimental until it has been tried in a real Foundry world) or TomeStack's own sheet JSON for any other tool. The preview says what is left out because it may not be shared (its totals stay), and which numbers Foundry works out itself and may show differently, and what the Foundry file cannot carry (such as the Pact Magic slot level). Spells arrive ready to prepare and cast with their own caster's ability; link and roll codes in exported text stay plain text. Every file carries the license notices of the sources it draws on, and never a folder path, a PDF link or a gap note. Nothing is uploaded. Roll20 has no supported import file and is not offered.

  • Extensions, without running any code (M6 slice 3, ADR-011; approved by the owner 2026-09-30): the Extensions screen installs an extension file after showing what it would be allowed to do; you tick each permission it may use, and can turn it off or remove it at any time. An extension is a set of instructions that TomeStack carries out itself, within strict limits. An import (for example a CSV spell list) becomes draft content in a new source that is never shared; an export (for example a Markdown summary of a sheet) leaves out content that may not be shared, keeps every license notice, and is checked for your folder paths and user name before it is saved. Every run shows its result before anything is written. The sample is in examples/extensions. Full backups keep installed extensions, which come back turned off with no permission granted.

  • Share a campaign as a campaign pack (M6 slice 2; approved by the owner 2026-09-30): "Share …" on the Campaigns screen saves the campaign's rules, allowed sources and house rules, with the published content of the homebrew you marked as your own work. The SRD is named, not copied, and every other allowed source is only named, with the reason shown before you save. It never carries characters or gap notes. Importing a pack for a campaign you already have asks whether to keep your version or use the imported one, and lists the characters whose content the imported one would no longer allow. A source the pack only names, and that you do not have, stays allowed and is shown as "waiting" until you install it.

  • Share your own homebrew as a source pack (M6 slice 1; its schema changes approved by the owner 2026-09-29): on the Sources screen, "Mark as shareable…" asks you to confirm that a source is your own work, and "Share sources as a pack" saves those sources with their published content: no characters, drafts, PDFs or text read from PDFs. Importing a pack shows the sender's statement and copies your library first. From this version on, a source that gets a PDF attached, pages imported or a PDF candidate accepted is marked for good as holding imported material: it is never shared, not in a pack and not in a character share, even after the PDF is removed. Sources from earlier versions are marked if they have a PDF now, had one before database version 3, or have an import job. The data folder moves to database version 8, and full backups to package format 7 (see Migration).

  • Snapshots of a character (M5 slice 8): "Take snapshot" on the sheet keeps a copy of the character to come back to. "Restore" first shows what would change. It then keeps a snapshot of the current state as well, so every restore can be undone. Snapshots stay on this computer: exports, shares and full backups leave them out. The data folder moves to database version 7; the previous version is backed up first (tomestack.db.v6.bak).

  • Design feedback, if you want it (M5 slice 7): a "Show design feedback" setting in the studio, off by default. When it is on, "Get design hints" compares a class or feature with the SRD classes. It points out more spell slots than any SRD full caster has, a multiclass share that gives more slots than the class's own table, a resource that grows faster than any SRD pool, and levels that give nothing. Hints never block publishing, never change a character and are never exported.

  • Start homebrew from a template (M5 slice 6): four starting points in the studio: a feature with limited uses, a stance you switch on and off, a subclass skeleton and a class skeleton. A template opens as an unsaved draft; nothing is saved or published until you do it. The skeletons leave empty feature slots at the usual levels, which you fill with your own published features. The studio can now also edit toggles, and bonuses that apply only while a toggle is on.

  • See how your homebrew fits together (M5 slice 5): "Show relationships" in the studio editor draws a tree. For a class it runs by level, through the features and choices it brings in, to the resources and to the rolls and rests that use them. It also shows what never applies, such as a grant inside granted content. It works fully by keyboard and with screen readers, and Enter on a rule jumps to it in the editor.

  • Compare two versions of your homebrew (M5 slice 4): "Compare revisions" in the studio editor shows what changed between any two versions, including the unsaved one on screen. It shows the rules and the texts line by line, and what each version would give copies of your characters (and a blank character, for a class or subclass). Nothing is changed. The update review uses the same calculation.

  • Try a class or subclass before you publish it (M5 slice 3): "Try it" in the class and subclass editors shows how the revision on screen plays, at a level you pick. It runs on a blank character or on a copy of one of yours, with the calculated sheet fields it would change. Nothing is saved, and your characters keep using published content only.

  • Find problems in your homebrew (M5 slice 2): "Find problems in " in the homebrew studio checks all of a source's content, drafts included, and "Find problems" checks the entry you are editing. It finds what the Check button cannot see on one entry alone. Examples: a resource nothing spends or recovers, a recovery or action for a resource that isn't there, a grant that never applies because the content is itself granted, a subclass no class offers, a class feature nothing grants, a choice with nothing to pick, class columns that are read but missing or defined twice, and grants of an older version. Show opens the entry and moves focus to the rule. Nothing is changed.

  • Write your own class in the homebrew studio (M5 slice 1b; ADR-010): "New class" sets the hit die, the saving throws and multiclass prerequisites. It can also set:

    • a skill choice (TomeStack creates the skill options for you);
    • a subclass choice at any level, which your own subclasses join;
    • class columns such as "Ink", which resources and other formulas can read;
    • features by level;
    • spellcasting with its own slot table and a caster share for multiclassing.

    The class appears in the builder like any other, and the sheet shows its columns under "Class columns". Content that uses these features can only be opened by this version of TomeStack or later.

  • Classes with their own columns and caster shares (M5 slice 1a; ADR-010; rules engine only): class content can now carry named per-level columns, such as "Ink: 2, 2, 3 …". Its formulas can read them, so a resource, a roll bonus, a skill or a prepared-spell count grows with the class. A caster can also say exactly how many caster levels it adds at each class level, for example two thirds, and it combines with the SRD casters on the Multiclass Spellcaster table. The homebrew studio cannot author these yet; that is the next slice. Tested on an original fixture class, not bundled content.

  • Archive a character (SPEC C-08, audit 2026-09-28): "Archive…" on the sheet first says what happens, then moves the character to a collapsed "Archived" list after you confirm. Nothing is deleted: its play state, gap notes, campaign and the content it uses all stay, and "Back up everything" includes it and restores it archived. "Unarchive" brings it back as it was. There is no hard delete. Exporting a character never passes on that it is archived, and importing a package never archives or unarchives one. Older versions of TomeStack show an archived character as active.

  • The Fighter and the armor table (M2.2; docs/licensing/srd-pack-review.md "M2.2 extension"): the SRD Fighter, levels 1–20, in both rules families, with the Champion, and the SRD armor and shield table.

    • Automated: Fighting Style as a choice (Defense adds +1 AC while you wear armor), and Second Wind, Action Surge and Indomitable as resources that come back on rests. Second Wind rolls 1d10 plus your Fighter level. Also automated: the number of attacks (Extra Attack) and the Champion's critical range. The Champion's second Fighting Style is a choice too, and a style can't be picked twice.
    • Armor: light, medium and heavy armor and shields set Armor Class as before. They now also warn when you lack the Strength (speed 10 feet lower) or the training, and Stealth warns about disadvantage. Under 2024 rules a shield without training adds nothing to Armor Class; under 2014 rules it still does.
    • Reference text, applied by hand: the other Fighting Styles, Weapon Mastery (the kinds you choose), Tactical Mind and Tactical Shift, Remarkable Athlete, Heroic Warrior, Survivor and Ability Score Improvements. The feature texts say what to do.
    • Homebrew: a homebrew Fighter subclass joins the Fighter's subclass choice next to the Champion, which is the path the Stardust Guardian will take.
    • Paladin and Ranger: their Extra Attack is now counted too, and their armor training is recorded (the Paladin's heavy armor only as a starting class), in new revisions. New Wizard and Sorcerer revisions record that they have no armor training. Existing characters get them through "Updates available".
    • Content schema v8 adds the fields this needs. Older content is unchanged, and older versions of TomeStack refuse v8 content with a clear message. Homebrew you publish is saved in the oldest content version that can hold it, so homebrew that uses none of the new fields can still be shared with TomeStack 0.3.x.
  • Back up everything and restore it (M2.1; docs/features/package-format.md "Full library backup", ADR-007 item 10): a new Backups screen.

    • Back up everything saves one file with your whole library: characters, campaigns, gap notes, all your homebrew (drafts, older versions and entries no character uses yet) and the PDFs TomeStack keeps a copy of. Before this, only characters and what they used could be backed up, so unfinished homebrew had no backup at all.
    • Restore full backup checks the whole file first, PDFs included, shows what it would add or replace, and restores only when you confirm. It deletes nothing. Before it replaces anything, it saves a copy of your current data in the backups folder.
    • A character's own export is unchanged, and so is its "Share with someone", which never includes PDFs or gap notes.
    • Character packages are still format v5, so TomeStack 0.3.0 can read them. Full backups are format v6, and older versions refuse them with a clear message.
  • M4 exit evidence (docs/features/m4-acceptance.md): the original fixture book is imported through the real worker in the gate, reviewed, and nothing is active without approval. The run on a third-party test PDF is prepared (it reads a private local folder and reports counts only) and still owed, so the version stays 0.3.0.

  • Import review (M4 D5; docs/features/pdf-import.md): on the Sources screen, a source of your own with a PDF has "Read the text and find candidates". Read some pages or the whole book, watch the progress, cancel or resume, and search the text. Then review the candidates, filtered by page, kind, confidence and status. Each shows its excerpt next to "Open page", what was read, what is unsure, and what it depends on. Edit it, accept it as a draft or as a reference entry, or ignore it. Accepted entries are drafts in the studio, where publishing checks them again.

  • Reviewing candidates (M4 D4; docs/features/pdf-import.md): before a candidate is accepted, TomeStack checks the entry it would become (rules, references, formulas) and shows what it depends on. It stays blocked while a field is unsure or a name it refers to is missing, until you edit it or accept it as a reference entry only. Accepting creates a draft; nothing applies until you publish it in the studio.

  • Candidate detection (M4 D3; docs/features/pdf-import.md): an import proposes candidates found in the book's text: spells, feats, class features, weapon and armor table rows, and class feature tables. Each has its excerpt, page, proposed rules, a confidence and what it is unsure of, and the names it mentions that are not installed. Nothing becomes content until you review it. Measured on the two SRDs: every spell is found with its level, and every bundled weapon and class is found.

  • Import jobs (M4 D2; docs/features/pdf-import.md): extracting a PDF runs as a job you can cancel and resume. It survives closing the app and keeps a local audit log with no text from the book. Extracted text is searchable within its source. Imported text stays on this computer: no backup or share includes it.

  • PDF text extraction (M4 D1, ADR-009; docs/features/pdf-import.md): TomeStack can read the text of a PDF page by page, with its layout, and reads pages without a text layer with Windows' built-in OCR. The reading happens in a separate worker process with size, page, time and memory limits, so a damaged or hostile PDF cannot take the app down. Nothing is imported yet: import jobs and candidates follow.

  • Third-party components: PdfPig 0.1.16 (Apache-2.0), and the Windows SDK C#/WinRT projection (Microsoft Windows SDK license) for OCR. The self-contained install grows by about 31 MB (ATTRIBUTION.md).

  • M3 exit evidence (docs/features/m3-acceptance.md): every M3 item is mapped to its executable acceptance. The exit gate is not met yet, because the owner's Stardust Guardian material and a played session are needed. The version stays 0.3.0.

  • Source updates (M3 C7, SPEC I-06; docs/features/publishing-and-updates.md): when a newer revision of something a character uses arrives, from an updated SRD pack or your own homebrew, the sheet's "Updates available" panel offers it. Review it to see what changes, then apply it or keep the current revision. Nothing updates by itself.

  • Gap notes follow-ups (M3 C5; docs/features/gap-notes.md):

    • Report a gap: a button on every feature and field fills in the gap note's "About" and puts the cursor in the text box.
    • All characters: a new "Gap notes" screen in the sidebar lists every character's notes, open first, with "Mark resolved" and a way to open the character.
    • Notes still stay on this computer and travel only in a personal backup.
  • Printable backup (M3 C4; docs/features/printable-backup.md): "Print…" on the sheet opens a print preview of the character: abilities, saves, skills, combat numbers, attacks, resources, spells, every feature with its source, page and manual step, and overrides. It ends with the license notices. Print it on paper or with "Microsoft Print to PDF" from the app's own print dialog. Gap notes are printed only if you tick them in. Nothing is sent anywhere, and no file path appears.

  • Combined multiclass spell slots (M3 C3, D04's M3 part; docs/features/spellcasting.md): a character with two or more spellcasting classes gets its spell slots from the SRD Multiclass Spellcaster table instead of recording the total by hand. Full casters count every level, and half casters (Paladin, Ranger) count half: rounded down under 2014 rules, up under 2024 rules. The trace shows each class's share and the table row. Pact Magic stays its own pool. Characters built before this keep their pinned SRD classes (and the manual step) until they take the update.

Changed

  • A measured performance baseline (roadmap T4, 2026-10-01; measurements only, nothing made faster):

    • A full level-20 character with three classes and over 300 spells is calculated in under a millisecond.
    • Importing a 500-entry homebrew pack takes about 65 ms.
    • Checking one such character for content updates takes 13–17 ms, the slowest step measured. It is noted for later, with the other findings.
    • Details and how to repeat the measurements: performance.md.
  • More checks that your data comes back exactly (roadmap T3, 2026-10-01; tests only, no behaviour change): TomeStack's tests now try thousands of generated characters, homebrew entries, formulas and libraries on every build. They check that saving and reading never changes a thing, including data from newer versions that this one doesn't understand, and that each content version keeps its fingerprint. They check that the same dice seed rolls the same, and that backups, source packs and campaign packs come back equal in a fresh data folder. They also check that an older data folder upgrades with every character, campaign, gap note and source kept (sources change only where an upgrade step says so) and one backup copy left. They found no defects. Details: testing/properties.md.

  • Docs record M5 and M6 as merged (2026-10-01; docs only, no behaviour change): the roadmap, backlog, feature notes and decision records now say that the M5 and M6 work is merged to main (2026-09-30), and that the package format numbers (7, 8 and 9) and database numbers (7, 8 and 9) are final. It is still checked on test fixtures only, not on an installed build.

  • Roadmap: use it first, then prove it (revision of 2026-09-29, reconciled 2026-09-30; plans only, nothing built): the next milestone is a played session with a written gap report (T2), after repository clean-up (T1), and then property tests, benchmarks, a real release and a restore drill on a second machine (T3 to T6). By owner direction, the M6 sharing and extension work already built stays; the played session decides what comes after it, including more content and anything in M7.

  • Status docs match the build (M6 follow-ups, 2026-09-30; docs and one test, no behaviour change): the ROADMAP's "plugin SDK sandbox" is noted as built as the declarative extension API (ADR-011 option A, nothing runs, so no sandbox); the backlog marks campaign packs and the Foundry export as built and unmerged, and the command palette and tags as optional after the M6 gate; and the e2e flow now checks that "Keep the current state" returns focus to the snapshot's button (item 23).

  • Licensing review covers the README screenshots (2026-09-30; docs/licensing/srd-pack-review.md): the builder screenshot shows SRD 5.2.1 text from the bundled packs, and the review now lists it with its pages under the same CC-BY-4.0 attribution.

  • Plans only, nothing built (ROADMAP "M5 plan" and "M6 plan"; LIVING_SPECS D13): by owner direction, M5 (creation power) starts before the M3 gate, which is unchanged and still not met. The template set and new effect types are provisional until the M3 gap notes arrive. The owner approved the plans and accepted ADR-010 (custom base classes, content schema v9). ADR-011 (the extension API) and ADR-012 (VTT export adapters) are proposed and wait for the owner's choices.

  • Content schema v9 approved (owner, 2026-09-29; ADR-010, LIVING_SPECS change history): the scale effect, SCALE.<id>, spellcasting.multiclassCasterTable and a choice with no declared options. Merged to main on 2026-09-30.

  • Correction to the 0.3.0 notes (2026-09-28): the 0.3.0 entry says the keyboard and Narrator passes passed on 0.2.2. Only the keyboard walkthrough was done. The Narrator pass, 200% zoom, High Contrast and the field-card state are still open WCAG AA checks (docs/features/accessibility-checklist.md, LIVING_SPECS D05).

  • Development switches are off in the shipped app (audit 2026-09-28; LIVING_SPECS D11): TOMESTACK_DEV_FIXTURES=1 and --devtools now work only in a Debug build, a smoke run included. The installed app also drops WebView2's extra browser arguments from the environment, so a variable or a shortcut can no longer seed test content into your library, open the browser developer tools or open a debugging port.

  • The development transport times out like the app's (audit 2026-09-28): in the browser dev setup, a command to the DevHost that gets no answer now fails after 30 seconds with "timeout", as in the desktop app, instead of waiting forever. Commands that wait for you (a native dialog) still wait.

  • Honest status (M2.1; README, MVP, ROADMAP, acceptance docs): claims now say how far they are proven: implemented, fixture-verified, Windows-install verified, or accepted in real play. The README states the current class, species and background coverage. M2 is "checks passed, limited content", because the MVP goal of any SRD character 1–20 is not met yet. The ROADMAP adds M2.1 (data safety, done) and M2.2 (Fighter baseline and SRD armor), and puts M2.2 before the M3 Stardust Guardian run that depends on it. PDF candidate import is labeled Experimental in the app until a real third-party book and the SRD measurements pass.

Fixed

  • Packages can no longer take over existing content (M6 stack review, 2026-09-30): a character package that adds a new version of an SRD or homebrew entry under a different source, or splits one entry across two of its sources, is refused (pack.content-conflict), as source packs already were. Before, the added version became the one new characters and update offers used. Only versions the package adds count, so your own backup of an entry that an earlier version split across two sources, or the copy saved before an import replaced a character, imports again on the computer that made it. The studio no longer saves a draft of an entry under a different source than the one it has (content.source-mismatch). A character that uses SRD content from a newer TomeStack says to update TomeStack instead of calling the content foreign. A package from a later TomeStack that adds a new kind of entry now asks you to update TomeStack instead of calling the file damaged.

  • Campaigns in character shares, and large campaign packs (M6 stack review, 2026-09-30): a character share now writes its campaign as a campaign pack does, without the list of sources waiting to be installed or properties this version does not know (a backup keeps both). Importing a campaign pack with a very long list of allowed sources no longer freezes TomeStack.

  • Design feedback compares only with the bundled SRD (review of #36, 2026-09-29): a revision you or a package added under an SRD source, or as a newer version of an SRD feature, no longer becomes the baseline of the hints.

  • No false "multiclass share above table" hint (review of #36): a class whose own slots skip a spell level (for example none of level 1, six of level 2) is compared by its highest spell level, not by how many levels have slots.

  • Older snapshots stay reachable (review of #36): the snapshot list shows 100 at a time, and "Show older snapshots" loads the rest, so a snapshot pushed down by many restores can still be restored.

  • The relationship tree no longer treats a draft as granted (review 2026-09-29): a grant or choice option that names a draft is shown with a note that characters get nothing from it until it is published, and content that extends a choice while a draft is marked as not offered yet.

  • Compare revisions review fixes (2026-09-29): a huge text that is too long to line up is now cut to a fixed number of lines and characters, and says "N more lines not shown". Compare now shows the problems a version resolves and the choices it leaves open, offers characters by the families of the two versions (and those with a recorded exception), and no longer sends a character you can no longer see.

  • Homebrew debugger review fixes (2026-09-29; docs/features/homebrew-studio.md): reach now follows the exact revision a grant or option names, as the calculator does, and every published revision that extends a choice; the scale problems still show when the walk is cut short; the "granted content's own grants never apply" note no longer hides that a character can pick the content directly.

  • Class editor (M5 slice 1b review): creating the skill choice again no longer publishes duplicate option features, the whole editor is disabled while it publishes, the rule list shows every multiclass restriction and saving throw grant the editor does not show, and a choice with no listed options can no longer ask for more than 20.

  • Content schema v9 (M5 stack review, 2026-09-29): a class column (scale) written in the wrong shape is refused when you check or publish it, instead of publishing with the column silently missing. Importing a package or restoring a backup no longer refuses revisions that publishing allowed: an inert scale in content an earlier build published, and a column id that clashes because of the order things were published, are warnings there.

  • A data folder always opens after an update (full-stack review 2026-09-28): if your library already holds different content under the id of a revision a new TomeStack version bundles (for example from a package imported earlier), TomeStack now keeps your copy, skips the bundled one and says so at startup. Before, it refused to open the data folder at all, on every launch.

  • Archiving no longer pulls you back: if you open something else while an archive or unarchive finishes, you stay where you went.

  • Fighter review fixes (M2.2, PR #12 review; docs/features/equipment.md, docs/features/multiclass-and-attacks.md):

    • Armor training is checked only when every class the character has levels in records it (and is installed). A Paladin who took a level of Fighter is no longer told they lack training for their plate, and under 2024 rules a Cleric who takes a feat granting light armor keeps the shield's Armor Class. A Wizard who takes a level of Fighter is still warned about heavy armor.
    • A roll's bonus keeps its sign: a Strength 8 bonus is −1, not 0. The button shows it as "1d6 − 1", and the roll record calls it " bonus" instead of showing the formula. A bonus that cannot be worked out for the character is shown as a problem on the feature, and the roll is refused instead of rolled without it.
    • The critical range stays between 1 and 20, and the number of attacks is at least 1, with a warning when content goes past that. Homebrew can lower the critical range only with a bonus (a "set" or "replace" would keep the highest value, which is the wrong way round), and can't make an Armor Class replacement that applies only in armor (it could never apply).
    • Content that claims an older content version but carries the new Fighter fields (including the attack count and critical range) has those fields ignored, as an older TomeStack would, with a note on the sheet.
  • CI (M2.1): the UI flow no longer fails at random. Five checks read the status line before it changed and saw the previous message (three failed runs on 2026-09-28). They now wait for the expected text, and lint refuses the old pattern in the e2e tests. A sixth race: the Barbarian flow read the long-rest proposal as soon as the panel had focus, before the proposal had arrived (reproduced by delaying it 400 ms), and that flow took 23 of its 30 seconds. It now waits for the proposal, and e2e tests have 60 seconds. The desktop smoke is now blocking: it passed on every hosted run that reached it. A new check starts two real TomeStack processes on one data folder. It passed three hosted runs in a row, so it is blocking too.

  • CI (M5 stack, 2026-09-29): the UI flow failed at random steps on the hosted runner (#30, #31 and #35 each had a red run on a commit whose rerun passed), always where a step waited the default 1 second for the DevHost. Every wait in the e2e flow now allows 10 seconds (e2e/timeouts.setup.ts); a 200 ms limit reproduced the same failures locally.

  • A second spellcasting class gets its bonuses, with a trace (M2.1; docs/features/spellcasting.md): a bonus to spell attacks or spell save DCs (from an item or a feature) used to reach only the first spellcasting class. A multiclass character's other casters showed a bare proficiency bonus + ability modifier, without saying how it was calculated. Every caster now gets those bonuses, and the Spells panel explains each caster's attack bonus and save DC step by step.

  • One TomeStack per data folder (M2.1; ARCHITECTURE "Data folder"): starting TomeStack again while it is open now brings the open window to the front instead of opening the same data a second time. Before, the second copy marked the first copy's running PDF import as interrupted, so resuming it could run two imports of one job at once. Its start-up clean-up could also delete a PDF the first copy was still attaching. TomeStack now holds tomestack.lock in the data folder while it runs, and Windows releases it when TomeStack exits or crashes. The DevHost is refused on a folder the app has open, and the app on one the DevHost has open.

  • Import review fixes (M4, independent review 2026-09-28; ADR-009, docs/features/pdf-import.md):

    • A page that crashes the worker, runs out of time or memory, or cannot be read by OCR now fails alone: it is marked unreadable and the rest of the book is read. Resuming used to stop on the same page every time. After 5 such pages in one run the import stops, and "Resume" continues after them.
    • What one page can send to the app is now bounded: the character limit covers its blocks and lines too, and the app refuses any worker message longer than a page can hold. The app also checks that the worker really runs under its memory cap before it reads the PDF, watches committed memory as well as the working set, and a worker left behind by a crashed app now exits.
    • Finding candidates holds a bounded amount of text in memory. A job past it detects its first pages and says so in its audit; import the rest as a page range.
    • Cancelling an import, or removing its PDF, now also stops candidate detection.
    • Accepting a candidate saves the draft and marks the candidate accepted together, so a crash cannot lead to a duplicate draft.
    • Importing the same PDF into the same source again no longer proposes entries you already accepted or ignored.
    • A linked PDF that changed on disk is caught when a run starts, not only when it is resumed.
  • Accessibility (import review): after you accept or ignore a candidate, focus returns to the candidate list instead of being lost, and the final import status ("completed") is announced.

  • Builder choices and spells: ticking two options quickly (two skills of a choice, or two spells) could drop the first one. Each tick now applies to the latest draft. This also made an end-to-end test flaky.

Migration

  • Database schema 9 (M6 slice 3; approved by the owner 2026-09-30) adds the extensions table. The data folder is backed up first, once, at the version it is opened with (tomestack.db.v8.bak, tomestack.db.v7.bak from an M5 build or tomestack.db.v6.bak from 0.3.x). After the upgrade, older builds refuse the folder; restore that backup to go back.
  • Package format 9 (M6 slice 3; approved by the owner 2026-09-30): a full library backup that keeps installed extensions (extensions/<sha256>.zip, without their grants; docs/schemas/package-manifest.v9.schema.json). A backup with no extension is still written as v7. Older builds refuse v9 files.
  • Package format 8 (M6 slice 2; scope campaign and pendingSources approved by the owner 2026-09-30) adds campaign packs (scope: "campaign", docs/schemas/package-manifest.v8.schema.json). Only campaign packs are written as v8; older builds refuse them. A campaign may now carry pendingSources (campaign schema v1, optional; older builds keep it as an unknown property). No database migration. A character package that replaces a campaign now copies the database first (backups/pre-import-*.db).
  • Database schema 8 (M6 slice 1; approved by the owner 2026-09-29, LIVING_SPECS D14) adds sources.import_derived, which can only go up, and marks every existing source that has a PDF, had one before database v3 or has an import job. Those sources stop being shared. The data folder is backed up first, once, at the version it is opened with (tomestack.db.v7.bak from an M5 build, tomestack.db.v6.bak from 0.3.x; an upgrade of several versions writes no copy per step). After the upgrade, older builds refuse the folder; restore that backup to go back.
  • Package format 7 (M6 slice 1; scope source approved by the owner 2026-09-29) adds source packs (scope: "source"), and full library backups are written as v7 because their sources carry importDerived, origin and shareConfirmedAt. Older builds refuse v7 files. v6 backups still restore; a source that comes back with a PDF is marked import-derived. Character packages stay v5 and leave the new fields out.
  • Database schema 7 (M5 slice 8; approved by the owner 2026-09-29, LIVING_SPECS change history) adds character_snapshots, insert-only (triggers refuse updates and deletes). The data folder is backed up first (tomestack.db.v6.bak). After the upgrade, older builds refuse the folder; restore that backup to go back. Packages and library backups are unchanged: snapshots are never in them.
  • Database schema 6 (M4 D2) adds the local import tables (import_jobs, import_pages, import_candidates, import_audit). The data folder is backed up first (tomestack.db.v5.bak). After the upgrade, older builds refuse the folder; restore that backup to go back. Packages are unchanged.
  • Content schema v7 (docs/schemas/content-revision.v7.schema.json) adds spellcasting.multiclassCaster. It is absent by default, so older revisions are unchanged. 0.3.0 refuses v7 revisions.
  • Content schema v8 (docs/schemas/content-revision.v8.schema.json, M2.2) adds the Fighter fields and armor.none. content.publish now writes the lowest version a revision needs (at least v3) instead of the current one; the draft keeps its version and no stored revision or hash changes (docs/schemas/README.md "Versioning rules", docs/features/package-format.md).
  • SRD packs (M2.2): new v8 revisions of the Paladin and Ranger (Extra Attack, then a further revision adding armor training) and of the Wizard and Sorcerer (armor.none), in both families (insert-only: a data folder opened by an earlier build of this branch still opens).
  • SRD packs: new revisions of the seven SRD slot casters and their Spellcasting features, in both families (insert-only; the earlier revisions stay for the characters that pin them).
  • Content schema v9 (docs/schemas/content-revision.v9.schema.json, M5 slice 1a, ADR-010) adds the scale effect, SCALE.<id> in formulas and spellcasting.multiclassCasterTable. Each is read only in a v9 revision. No stored revision, hash or bundled pack changes, and there is no database migration. Content published without these features keeps its lower version, and older builds refuse v9 content (content.schema-unsupported, package.schema-unsupported).

Download

  • TomeStack.App-win-Setup.exe: the installer (per-user, no admin rights, Windows 10 and 11, 64-bit). Windows 10 is best-effort.
  • TomeStack.App-win-Portable.zip: the same build without installing.
  • The .nupkg and releases.win.json files are Velopack's package and feed. You don't need them; TomeStack never downloads updates by itself.

This build is unsigned. See the note at the top about the SmartScreen prompt. Third-party notices are in ATTRIBUTION.md next to TomeStack.exe. Two Microsoft Windows SDK files that ship with TomeStack (Microsoft.Windows.SDK.NET.dll, WinRT.Runtime.dll) are covered by the Microsoft Windows SDK license terms. By installing TomeStack you agree to those terms for those files; see "Terms for the Microsoft Windows SDK files" in ATTRIBUTION.md.