Sharpee
Roadmap & Releases / Release notes

Release notes

Every published Sharpee release, newest first. A release is listed here once it is on npm — a version that was bumped and never published does not appear, because these notes describe what you can actually install.

Current: Sharpee 5.4.0 · Chord language 3.6.0 · Chord Writer 1.4.0. The three move independently (ADR-257): a platform patch does not touch the language, and the language version moves only when the author-visible surface changes.

5.4.0

the explicit ending release2026-09-11Chord 3.6.0

The end of a story is now something the platform can say. It had four names and no owner — a world-state flag, the story.victory/story.defeat events, the engine's own game.won/game.lost pair, and a Story.isComplete() hook polled once a turn — so five different places re-derived the same fact and none of them held it. A player who reached an ending in the browser could not type restart, and reloading the page put them back in the same dead prompt. The ending is now a first-class member of the world, declared by one verb, and the three defects behind that report close with it.

  • The ending is a record on the world (ADR-347): IStoryEnding carries the kind, the turn, the ending phrase's message id and a cause, and it is absent while play continues. A story that has not ended has no Ending, which is a different statement from one that says nothing.
  • One verb declares it. endStory(world, kind, opts) sets the Ending and returns the blessed ending event, and Chord's win/lose lowers onto it rather than carrying its own implementation — the same shape kill has always had with killPlayer. The first ending wins: a second call on an ended world writes nothing and emits nothing.
  • Story.isComplete() is gone. An ending is declared at the moment it becomes true, never polled for once a turn. Nothing in the tree actually polled for completion, and an optional hook that could report complete while the world carried no Ending was the split state the change exists to prevent.
  • The engine reads the Ending instead of recomputing it. The turn's ending stage used to reconstruct the answer from three unrelated sources every turn; it now asks the world one question.
  • A Chord lose ends the story as a defeat. It previously set the world flag, which the completion poll read, which stopped the engine as a *victory* — the engine only ever watched for story.victory.
  • Every ending reports itself. A death is declared by the engine rather than by the story, and it now emits story.defeat onto the turn's event stream like any other ending, where before it recorded the Ending silently.
  • The engine's phase is derived from the Ending when a save is restored: a save carrying an Ending restores stopped, one without it restores to play. That retires the reconciling patch 5.3.2 needed, and it is why RESTORE and UNDO now work at an end-game prompt.
  • Clients are told in state, not in prose. A new story-ending channel carries the record, alongside the existing endgame notification it deliberately does not replace, and the browser drives its input box from it — disabled when the story ends, live again the moment a restore or undo returns the player to a turn they can type into.
  • The end-game prompt comes from the language layer, derived from the same Ending, so every host gets it rather than each client inventing one.
  • Reloading an ended game no longer strands the player. The ended world is still saved, faithfully; what changed is that the reload lands at an end-game prompt that works, instead of the save being suppressed to dodge a state the platform could not represent. ## Upgrading Breaking, which is why this is a minor rather than a patch:
  • Story.isComplete?() is removed from the Story interface. A story that ended itself by returning true from it calls endStory(world, kind, { turn }) at the moment its condition becomes true.
  • ChordStory.triggerEnding and RuntimeHost.triggerEnding take (world, ending, turn, messageId?) and return ISemanticEvent | undefined — undefined when the story had already ended.
  • TurnStageContext.victory is removed. A hand-emitted story.victory event no longer stops the engine on its own; endStory is the declaring route.
  • A Chord lose now ends as a defeat rather than a victory, and a death turn emits story.defeat.
  • New public surface: IStoryEnding, endStory, WorldModel.getEnding/setEnding, the story-ending channel, and EndGamePrompt. Saved games written before this release carry the old world-state flag and are not read for an ending. No story has been released, so no save in the world needs migrating, and no compatibility shim ships.

Traces to: ADR-347 · ADR-345 · #414 · #415 · #416

5.3.2

the Chord playable release2026-09-11Chord 3.6.0

The Chord playable keyword finally reaches the runtime. It had been in the language since 2026-08-26 and the analyzer had enforced it from that day, but the loader step that writes the flag onto the actor was never built and the trait defaulted to *true* — so every actor in every story read as playable, and the guard that checks it could never fire. Connecting it opened three more seams, and all four are in this release.

  • The player role holder is validated where the story is installed (ADR-344): it must exist, be placed, carry an actor trait, and be playable. The loader's old fallback of dropping an unplaced protagonist into the first declared room is gone — every story places its own.
  • The engine is never handed a player. GameEngine no longer takes one at construction; it comes from the story source, for Chord and TypeScript stories alike.
  • ActorTrait.isPlayable now defaults to false, matching what Chord means by the word's absence. A protagonist built through the author-facing builder says so with .playable().
  • The engine's lifecycle is an explicit phase — empty → ready → playing ⇄ stopped (ADR-345) — rather than something each method re-derived from whichever field was nearest. resume() emits game.resumed, which it previously did silently.
  • Traits no longer police completeness (ADR-346): a door may be one-sided and an exit half-built while a story is still composing the passage. Detection belongs where the world is checked as a whole.
  • Gate work rode along: pnpm typecheck became a real gate (it had been compiling zero files), test files entered it, seven packages' suites entered the test:ci sweep, and engine tests stopped running on the wall clock.

Traces to: ADR-343 · ADR-344 · ADR-345 · ADR-346 · #400 · #401 · #402 · #404 · #410

5.3.1

the refactoring survey2026-09-10Chord 3.6.0

A patch release carrying a structural survey of the platform: seven ADRs, each naming one package's shape and fixing it. No author-visible syntax moved, which is why Chord stayed at 3.6.0 and this went out as a patch rather than a minor.

  • ADR-334: the turn is a stage list. game-engine.ts gave up its turn helpers, one platform dispatcher and one enrichment funnel replaced duplicated pairs, and the package reorganized into command/, install/, session/, ports/ and introspection/.
  • ADR-342: the engine's root barrel narrows to a contract — 31 named exports, no export *. A type reachable only through a kept export's signature stays internal.
  • ADR-337: the interceptor lifecycle has exactly one call site, the executor's phase runner, and one validation pipeline replaced two.
  • ADR-338: AuthorModel became a proxy view of the live world rather than a parallel one.
  • ADR-339: the character tick's seven sub-steps live beside the subsystems they belong to, as a list with per-step requirements, pinned by a test.
  • ADR-340: transcript-tester and branch-tester share one assertion core instead of 1,129 identical forked lines.
  • Chord Writer 1.4.0 ships alongside.

Traces to: ADR-334 · ADR-335 · ADR-336 · ADR-337 · ADR-338 · ADR-339 · ADR-340 · ADR-342 · #376

5.3.0

publish-readiness, and the acting statement2026-09-04Chord 3.6.0

The largest release of the 5.x line, and the first that was measured against a specific question: what does an outside author writing a modest Chord story hit in their first hours? Forty defects were triaged into a plan and worked through in sixteen phases. Underneath it, ADR-327 made clause heads name who acts, ADR-328 threaded an actor through the whole standard-action library, and ADR-329 gave Chord the acting statement — one character performing one real action, validated and interceptable, through the same execution entry a player's command takes.

  • 5.2.0 is not missing. It was bumped on 2026-08-29 and never published; everything in it ships here. That is why Chord went 3.3.0 → 3.6.0 in one step — 3.4.0 and 3.5.0 are landing history.
  • ADR-327 is a Chord major folded into this release: on <gerund> it is gone, clause heads name the actor (on the player taking, after Jack entering), and syntactic it/its left statements and conditions outside a define trait body.
  • The player became a role a named character holds: playable marks who is eligible, and change the player to <character> assigns it and can move it mid-play. create the player is gone.
  • ADR-325 places and timers; ADR-326's move <entity> to a random adjacent room; ADR-330's chapters extension; , one-way exits; proper on any create block.
  • The held command (a bare noun answering a disambiguation), possessive entity names in conditions, remove marking an entity *gone* rather than destroying it, and one-way exits are all publish-readiness fixes that an author meets early.
  • @sharpee/world-index arrived (ADR-321): a story's map, reach and vocabulary gaps derived as JSON, surfaced in Chord Writer's World tab.
  • Nested Chord imports (ADR-251 D5 amended), with Span.file so a diagnostic names the fragment it came from.

Traces to: ADR-325 · ADR-326 · ADR-327 · ADR-328 · ADR-329 · ADR-330 · ADR-332 · the publish-readiness proposal (40 items)

5.1.1

the ESM build, repaired2026-08-19Chord 3.3.0

A patch release almost entirely about the build. The ESM target was not being produced whole-tree, which broke vitest's ability to resolve dist-esm/ packages and, with it, the Chord Writer release pipeline. The fix makes the ESM build default-on and derives vitest's workspace aliases instead of requiring a prior dist-esm build.

  • Chord Writer 1.3.1 ships alongside, with its release pipeline working again.
  • #280: an opening card that could never be claimed.
  • Full card sets and walkthroughs for the conversation stories, and The Ides of March moves.
  • Author documentation for characters and conversation on sharpee.net, written against the syntax 5.1.0 had just shipped.

Traces to: #276 · #277 · #279 · #280

5.1.0

conversation2026-08-18Chord 3.3.0

The character model reached Chord. @sharpee/character had existed since April 2026 and passed its tests with zero consumers; ADR-310 and ADR-318 gave it a Chord surface, and ADR-320 built conversation on top across eleven phases. Authors can now write manner, greetings, exchanges, initiative and whole conversation threads in a .story file, and The Ides of March was written as the story that proves it.

  • Chord 3.1.0, 3.2.0 and 3.3.0 all landed inside this release: the conversation grammar arrived in three slices, each with its vocabulary frozen by the owner the same day.
  • NPC-to-NPC scenes, with earshot derived from spatial sound, player intrusion into a scene in progress, and mid-scene save/restore.
  • Trait-level conversation memory: what a character has been told, and how recently, is world state that persists.
  • Chord Writer gained an explain-NPC-turn panel — an author channel that reports why a character did what it did on a given turn.
  • Goals, influence and information propagation are in scope rather than deferred, on the owner's ruling that they are the point of the character model.

Traces to: ADR-310 · ADR-318 · ADR-320 · ADR-141 through ADR-146 (prior art)

5.0.1

Chord Writer ships its own toolchain2026-08-14Chord 3.0.0

A patch release whose real content is on the desktop side: Chord Writer became installable without a Node toolchain. The DMG now carries a per-architecture vendor toolchain, so the download page could drop the npm install step an author previously had to perform before the app would do anything.

  • Per-architecture build and packaging, with two download tiles on the site rather than one universal binary.
  • The app runs on any Apple silicon Mac, not only the machine it was built on.
  • Self-hosted analytics on sharpee.net, provisioned by the deploy with a salt that persists itself rather than rotating on every deploy.
  • The app icon arrived: parchment at large sizes, a single note at small ones, masked into the macOS tile shape.

Traces to: ADR-279 · ADR-284

5.0.0

the testing surface is the tree2026-08-11Chord 3.0.0

A new model for testing a story. ADR-307 replaced the transcript-shaped testing UX with a tree document — one <story-id>.tests.json per story, where the tree *is* the model rather than a view over something else — and @sharpee/branch-tester is the greenfield walker that replays it against a real engine. Chord Writer's Testing tab became the play surface itself rather than a panel beside one.

  • The tree document is a wire format with a schema, round-trip tests and discovery, shared by two consumers — the walker and the IDE — whose parity was signed off before the cutover.
  • JSON is the source of truth for a story's tests; the old transcript-shaped IDE artifacts went away rather than being kept in parallel.
  • ADR-309 made the IFID tool-owned: minted at story creation into <story-name>.config.json and rendered into the Chord header on save and build, so the compiler stopped asking authors for one.
  • @sharpee/transcript-tester stays, and keeps owning the .transcript grammar for Sharpee's own hand-authored suites. The two runtimes are for different audiences.

Traces to: ADR-307 · ADR-309 · #248