# Changelog

Notable changes to `@marver-design/marver`. Format follows [Keep a Changelog](https://keepachangelog.com); versions follow semver.

## 0.27.2 - 2026-10-24

0.27.1 was never published: its changes ship here, with 0.27.2's.

### Highlights

- **Leaving a canvas that holds unsaved work asks first, in every browser.** Chrome asked only while a Jam capture was
  being recorded, or on a stopped tab with board edits. Now a reload or a close asks whenever the page holds anything
  the canvas does not have yet: a capture recording, finishing or not taken by the canvas yet, a board edit not saved
  yet (a save on its way or one that failed), frame heights not written yet, or words typed and not sent (a comment, a
  Jam edit or note). A drag is not work until it drops. The page's own reload when its canvas comes back still goes
  without asking: it saves first. Chrome asks only on a page you have clicked or typed in since it loaded. A published
  canvas is unchanged.
- **A canvas opens where you left it.** A board you reload opens on the view you had, kept per project and board,
  unless the link names a selection: then it fits that, as before. The view is kept a second after it settles, and at
  once when the tab is hidden or closed; a tab hidden while the view is still flying (a fit, a zoom) keeps where it was
  going. A published canvas still opens on the whole board.
- **A board's first frame starts about 0.3 s sooner.** It waited 0.35 s after the board mounted, for the camera's first
  fit to land. It now starts as the fit sets off, chosen on where the fit will land, so it is the same frame. On a real
  project's boards the frames were ready 0.1-0.4 s sooner (a 30-frame board: 1.3 s to 1.0 s), and nothing moved more
  ([Performance](docs/performance.md#making-a-board-faster) has the numbers).
- **`npx marver perf run <board>`: a board measured the same way every time.** With `marver dev` running, the canvas's
  own headless Chrome loads the board once to warm up, then measures a load, a fit and three gestures (zoom in, zoom
  out, a pan that turns back), and writes one line: load to settled, frame times (p50, p95, frames over 33 ms), the
  heap's peak, and whether the run is valid, with the first reason it is not. A run is read-only: its page sends no
  write but its own records and the frames' sleep textures, and the dev server refuses any other. `--slow` throttles
  the CPU 4x, `--repeat <n>` runs it up to 5 times. `npx marver perf --runs` compares a run only with runs made the
  same way (board, Chrome, machine, power, `--slow`): the latest against the last with the same inputs and the last
  with others; `--against <run>` against one you name. Your agent is told to use it before and after a change
  ([Headless runs](docs/performance.md#headless-runs)).
- **The Mac app needs this version.** With it, the app asks before a close, a quit or a reload loses unsaved work,
  follows the canvas's theme, shows its View and Jam items in the menu bar and wears its logo on the tab; app 0.2 also
  runs the canvas full height under its transparent tabs. A 0.27.0 canvas opens in the app with a lesser
  guard and none of the rest. In a browser, none of the app's side runs.

### Changed

- **Reduce Transparency and Increase Contrast make the glass opaque.** With either set in macOS, the sidebar, the
  toolbar and every glass surface take a solid fill and a plain border; with Increase Contrast the dimmer text takes the
  full ink. Chrome reads the same settings.
- **`npx marver perf --loads` names each board as the sidebar does, and its two clocks apart.** A load is headed by its
  board's title ("v1 lo-fi - Mac and iPhone", not "Journey"; `--json` keeps the board's name). A settled load says
  `still from` its last move, where it said `quiet 0.0 s · last move 1.3 s`, which read as a contradiction. `slowest`
  is now `slowest to settle`: a frame's time to its last height, which can come after `all ready`, each frame's first
  render. [Performance](docs/performance.md) says what settled means.
- **The logo ladder reads `public/favicon.png` and `public/favicon.ico` too, and a logo must be one.** After
  `share.logo`, `design/logo.svg|png`, `public/logo.svg|png` and `public/favicon.svg`, `marver build` now tries
  `public/favicon.png` and `public/favicon.ico`. A candidate counts only as a regular file inside the repo (never a
  symlink, even one inside it) of at most 256 KB whose bytes are an SVG, a PNG or an ICO; its type comes from its
  bytes, so a PNG named `.svg` is published as `logo.png`. A `share.logo` that fails is ignored with one line saying
  why; 0.27.0 followed a symlink and copied `share.logo` from anywhere. A gated `marver serve` shows a `logo.ico` before
  sign-in, as it does a `.svg` or `.png`.
- **`marver ls` names a canvas as the canvas does**: `share.name` when you set one ("TMS broker", not "tms-broker"),
  else the folder name.

### Added

- **The Mac app's bridge.** In the app, a canvas page tells the app what it holds, so closing its tab, quitting or
  reloading asks first or waits; its theme, which the app's tabs follow; and its View and Jam menu items with their
  keys. When its tab is shown again it reads its marks, its agents' work, the Jam queue and its board again; when the
  app stops trusting it, it lets go of the microphone at once, one still opening too. Each canvas's file in
  `~/.marver/running/` lists `bridge` and `inset` among its features.
- **Under the Mac app's tabs (app 0.2).** When the app places a canvas full height under its transparent strip,
  everything you read or click stays below the strip: the sidebar, the toolbar, the Jam panel and sheet, play's pills
  and the stopped banner sit 44 px lower; the selection bar, tooltips and menus never go above it; a fit, a frame's
  focus and play's stage leave its room. The canvas's own ground and dots run under the strip and fade out just below
  it, and a frame under it counts as out of view (not marked seen, not named to Jam). Everywhere else (Chrome, a
  published canvas, `marver shot`, app 0.1) nothing moves.
- **`npx marver perf --crashes`, `--flashes` and `--machine` read the Mac app's records** (app 0.2), joined to this
  repo's board loads: each canvas crash with its board, whether its load had settled and the last gesture before it;
  each flash you marked with ⌃⌥F, with the gesture it fell in and the GPU process's events around it, the white-out
  candidates apart; the machine profiles by host. In the app the canvas tells the recorder its gestures, so its
  records land on the right board load. `--days <n>` (14) for these and `--runs` ([The Mac app's
  half](docs/performance.md#the-mac-apps-half)).
- **`GET /__mv/logo`** on `marver dev`: the canvas's logo, from the same ladder and checks as `marver build`, signed
  when the app asks, so the app shows a logo only from the canvas it verified.

### Fixed

- **"Back - your edits were saved" every time.** A tab that held an edit when its canvas stopped saved it when the
  canvas came back and reloaded, but said so only when the save it made on the way back carried the edit. Often the
  ordinary autosave had already saved it (a frame still in your hand when the canvas answered, then dropped) and the
  reloaded page said nothing, though the edit was on disk. Now every board save between the stop and the reload
  counts, and a lost one too: the reloaded page then says the file won, or that the board is gone.
- **A tab whose canvas came back reloads only once its heights are saved.** A heights write that failed on the way back
  was dropped by the reload. Now the tab reloads once every height has reached `_sizes.json`; until then it works as
  live and sends them again.

### Upgrading

`npm install @marver-design/marver@latest`, then `npx marver init` to refresh the agent instructions (they compare a
board before and after a change with `npx marver perf run`, and say what counts as a logo). Restart each canvas: the
Mac app sees the bridge only on a canvas started from this version.

## 0.27.0 - 2026-10-23

### Highlights

- **Each canvas takes a slot: localhost:4805 to 4824.** `marver dev` no longer works its port out from the folder's
  path (5200-5399). It takes one of twenty fixed ports - this project's last one when it is free, else the first free
  one - so a project usually gets its address back. A port another program holds is skipped, and said; with all twenty
  taken it stops before starting, lists them and says how to free one. A canvas that ran before says where it moved on
  its first start: "ports are now fixed slots: this canvas is at http://localhost:4806/".
- **`npx marver ls`** lists the canvases running on this Mac - slot, link, name, version, state, uptime, folder - with
  `--json` for agents (never a canvas's key). It needs no repo and leaves out a canvas that died without stopping; one
  that has begun to stop shows `closing` and holds its slot until it has gone.
- **A tab left open can no longer write into another project.** A tab whose canvas had stopped kept talking to
  whatever started next on its port, and could save its board into another project whose board file matched. Now every
  request it makes, and every frame, play-stage and Jam-picture address, names its project, and another project
  refuses them before reading or writing anything. The tab says what happened and the way back ("This canvas stopped -
  run npx marver dev to bring it back"), and that your unsaved edits are kept in it when it holds some; comments and
  Jam captures wait for the canvas. When its canvas answers again, the tab saves, then reloads on the view you had
  once nothing is in progress (a capture, words not sent, a drag): "Back - your edits were saved". If the board's file
  changed on disk meanwhile, the file wins, as it always has, and the tab's unsaved board edits are lost ("board
  changed on disk - canvas layout reloaded"); a board renamed or removed meanwhile is not created again. Leaving a
  stopped tab with unsaved board edits asks first.
- **`npx marver perf --loads`** says what each board load did, from the page: the time until the frames in view were
  ready, until all were and until the board settled, or why the load was cut; how often the board moved and why; the
  five slowest frames, each with its wait in the queue and its own time; errors, and frames that never answered or are
  missing. `--json` for agents; plain `marver perf` adds a line per load. Its record (`design/.local/perf/page.jsonl`)
  can hold file paths, so it stays on your machine; it costs nothing at rest ([Performance](docs/performance.md)).
- **Pictures work with Chrome 156.0.8078.47 and later.** That update made a headless page read as hidden when another
  window covers it, and each picture has a window of its own, so a picture could wait on a paint that never came.
  Marver's Chrome now runs every page as if seen (`marver shot`, agent pictures, copy as image, video posters, Jam).
- **Your agent keeps the canvas up.** A canvas an agent starts dies with its job (Claude Code stops a background job
  after 10 minutes), and the link it gave you with it. The agent instructions now say: `npx marver ls` first; none
  running, ask you to run `npx marver dev` in your own terminal; if it starts one, detached so it outlives it (output
  in `design/.local/dev.log`), its link read from `npx marver ls`. Where a sandbox keeps the canvas from starting or
  being reached, the agent asks you to run it; `marver shot`, `marks`, `ls` and `perf --loads` still work there.

### Changed

- **A port you chose stays yours.** `--port <n>`, or a `port` in `design/config.ts` other than the scaffolded 5199, is
  tried first, as before; when it is taken, the canvas takes a slot and says so. A port in 4805-4824 claims exactly
  that slot: when something else holds it, `marver dev` stops and says what. A port from `design/config.ts` is named
  as the canvas starts ("remove it to use the slots"); a new `design/config.ts` has it only as a commented example.
- **A start that fails leaves nothing behind.** Its lock, its slot, a half-made server and the watchers are given
  back; it says what failed ("port 4806 was just taken by another program - start again", for one) and exits with 1.
- **`marver dev` says when it stops**: "canvas stopped - open tabs keep their edits and save when it is back".
- **One project key, the one 0.26 used.** Marver names a project by one key, made from the folder's real path - 0.26's
  key for a canvas started with `npx marver dev` - so a capture waiting in a page keeps it; only the address moved.
- **Five viewer preferences are kept per project.** Your view theme, the update notice you closed, the mentions you
  opened, which sticky notes show and which folders are folded were kept per address, shared by projects that ran
  there in turn. A local canvas now keeps them per project at each address and carries them nowhere else: they start
  fresh after the upgrade, and on a slot the canvas has not used before. A published canvas is unchanged.
- **No service workers on a local canvas**: an address is reused by whichever canvas starts there next, and a worker
  would outlive its canvas. A PWA prototype shows its screens, not its offline behaviour.
- **`__mvPerf.report()` has new names:** `over33ms` (a count) and `over17ms` replace `dropped` and `droppedFrac`;
  `longTask*` become `longFrame*`.
- **The frame-time sampler rests with the canvas:** it runs only during a pan, a zoom or a layout animation.

### Added

- **`npx marver dev --recover`** starts a canvas on an address it ran on before - exactly its port, the address it
  bound and the project key that run used, never another - so a Jam capture left unsent in that browser sends itself.
  Alone it lists the last five addresses, newest first, then the one 0.26 gave the folder; `--recover <n>` starts on
  one; `--recover --port <p>` on the port 0.26 moved to. A canvas whose slot was taken says where it ran last time,
  which canvas runs there now, and that a tab still open there keeps its unsaved edits (and an unsent capture waits)
  until this canvas runs there again: "stop "atlas" and this canvas, then `npx marver dev --recover 2`" ([A capture
  left on an old address](docs/jam-session.md#a-capture-left-on-an-old-address)).
- **The document proof.** An app that opens the canvas page can check the page comes from that canvas: send
  `x-mv-nonce`, get `x-mv-instance` and a signed `x-mv-proof` back. Without the header nothing changes.
- **`MARVER_HOME`** moves `~/.marver` - running canvases, slot preferences, collaboration credentials - and
  `marver ls` reads it too. The speech model stays in `~/.marver/models` (`MARVER_MODELS` moves it).

### Fixed

- **Editing `.env` no longer stops Live Jam.** Vite restarts the canvas's server in place when an `.env` file changes,
  and 0.26 took that for a stop: Live Jam stopped, comments written from the terminal no longer reached the page at
  once, and `marver shot`, `work` and `link` lost the canvas. Now only the server restarts.
- **A link, back or forward reads its board once**, not twice (each fires two browser events).
- **The demo frames show their bottom button whole**: `welcome` and `dark` ran past the frame and cut it off.
- **A frame's error card comes from the document it shows**: a late error from a document it replaced is ignored.
- **The dev server never serves `~/.marver`**, which holds the running canvases' keys and the collaboration
  credentials - not even when your project's workspace root is your home folder.
- **In a sandbox, `marver dev` says why it cannot start.** Where every file watcher fails (`EMFILE` in Codex's
  sandbox), it ended with Node's own error; it now says to ask the person to run `npx marver dev` in their own
  terminal and exits with 1, leaving nothing behind - as when a watcher fails later.
- **A canvas out of reach is not "not running".** In a sandbox that keeps an agent off localhost, `marver link` said
  the canvas was not running, an invitation to start a second one. When `design/.local/dev.json` names a process that
  runs, `link` prints the link and says the canvas runs but cannot be reached from here; so do `work start` and
  `work done`.
- **The perf logs are yours alone**: `design/.local/perf/` is mode 700 and its files 600, older ones included; at
  start each log loses lines older than 14 days, and past 2 MB its oldest half (`page.jsonl` keeps 8 MB).

### Upgrading

`npm install @marver-design/marver@latest`, then `npx marver init` to refresh the agent instructions (they find the
canvas with `npx marver ls`, ask you to start it in your own terminal or start it so it outlives them - never with a
port - and read `npx marver perf --loads`). **Before you upgrade**, open each canvas once in the browser you make
captures in, with its old version still running and Live Jam on: a capture left unsent there sends itself. One left
behind comes back with `npx marver dev --recover`. On its first start each canvas moves to a slot and says where; a
bookmark to its old address no longer reaches it (`marver ls` lists the new one). A `port` you set in
`design/config.ts` stays until you remove the line. The five viewer preferences start fresh. **Then close every tab a
0.26 canvas opened** (send or save what they hold first) and open the canvas again from its new link: a page 0.26
served names no project in its requests, so the protection above - a stopped tab that never writes into another
project - covers pages loaded from 0.27 on, not those older tabs.

## 0.26.1 - 2026-10-20

### Fixed

- **Pictures are what the frame shows** ([#14](https://github.com/TNEP4/marver/issues/14),
  [#24](https://github.com/TNEP4/marver/issues/24)). About one picture in thirty at 2x - and a very tall frame almost
  every time - came back as the frame's top-left corner repeated across the image, with nothing to say it was wrong.
  Headless Chrome copied its view before resizing it for the picture and tiled the old copy. Each picture now gets a
  window of its own, and a fixed-size frame or a slide has its window sized to the picture first, so there is nothing
  left to resize: in 900 pictures, none came back tiled (31 did before). Every picture - a tall content frame's too - is
  also checked for that tiling; one that still shows it is taken again (a tall one at 1x if need be), and if it never
  comes out right the shot fails instead of shipping a wrong picture. This covers `marver shot`, your agent's
  pictures, copy as image, video posters and Jam's before and after pictures.
- **Content frames keep their diagrams** ([#7](https://github.com/TNEP4/marver/issues/7)). A state, sequence, gantt or
  pie diagram - or a first `Md` - could fail with "Failed to fetch dynamically imported module" until `marver dev`
  restarted. Another Vite server on the same project (your app's own, for one) was replacing the files the canvas had
  prepared. The canvas now keeps its own folder for them, `node_modules/.vite-marver`. The first chart frame also loads
  much faster: its chart library is prepared up front (about 40 requests instead of 600).
- **A capture outlives its page.** Closing or reloading the tab while a capture was recording or finishing used to
  lose it. Now it is kept as it stood - with your notes, and a line saying the page closed before it finished - and
  comes back as a draft to read, resume or drop. It never goes to your agent on its own, even with
  `jam: { capture: "at-once" }`.
- **`marver shot` works inside a sandbox.** An agent whose sandbox blocks the network (Codex) could not reach the
  canvas and said it could not look at its work. The command now takes the same picture through the canvas's file
  inbox when it cannot connect, with the same output.

### Added

- **`npx marver perf --jam`** shows how long each step of Jam takes on your machine - a capture sealing, its pictures,
  your words, naming, the queue, your agent, the pictures before and after, the reply - with the median, the slowest
  and anything that went wrong lately. It reads `design/.local/perf/jam.jsonl`: numbers and fixed codes only, never
  your words, kept on your machine.

### Changed

From a first long real Jam session:

- **Review shows before and after at once.** Side by side for a tall frame (a phone), one above the other for a wide
  one (a laptop), and the panel grows as wide as that takes, up to the window. **Both · Before · After** shows one
  alone; `B` steps through them.
- **The lane stays readable when full.** Its tiles lost their frosted blur exactly when the lane scrolled (its edge
  fades cut them off from what was behind); the fades are now strips of their own, and the tiles a touch more opaque.
- **Done captures fold into one tile.** With two or more done, one **Done** tile - "4 captures · 6 frames changed" -
  keeps the lane for what still needs you. Click it (or `⏎` with `Q`) to open them, a collapse tile folds them back.
- **The laser is a pointer.** `L` now lights only the element under the cursor, as comment mode does; a click still
  copies its path (or, in a capture, is its pick). The old laser, every element outlined, is **inspect**: `⌥L`, or
  ⌥-click the laser button. `Esc` turns a laser off before it closes or drops anything.

### Upgrading

`npm install @marver-design/marver@latest`, then `npx marver init` to refresh the agent instructions (a sandboxed agent
now knows `marver shot` reaches the canvas through the file inbox). The first `marver dev` after the upgrade prepares
its new `node_modules/.vite-marver` folder (a moment, once).

## 0.26.0 - 2026-10-20

### Added

- **Captures: talk through the canvas.** Press `S`, point at things, click through the
  prototype and say what is wrong, then `E`. A capture records your words, every click, pick
  and note, the screens and devices you went through, and pictures of the frames you touched -
  at the size you were looking at them - and your agent works from that one record. Its
  read-back lets you fix a word, add a note after the fact, and decide: `⏎` add to queue,
  `K` keep, `R` resume (it ended too soon), `Esc` drop
  ([Jam sessions and captures](docs/jam-session.md)).
- **A lane, and review with before and after.** Captures line up along the bottom of the canvas
  in the order you made them - queued, working, ready to review. A soft chime says one is ready;
  `V` opens it: the agent's reply beside each frame it changed, `B` flips before and after, a
  frame it made is marked New, and a Capture tab shows what you recorded. `⏎` looks good, `⇧⏎`
  sends it back with what is still wrong. When you asked for something new beside a frame, the
  capture's thread moves onto the new frame.
- **Sessions.** `J` runs a whole review as one session: it starts recording at once, keeps the
  canvas lit with a clock while you work, and listens between captures. `J` again wraps up - you
  say how to take it in, and your agent writes the record to `context/sessions/`: what was
  asked, what was done, what is left, the decisions heard.
- **Words, on this Mac.** What you say becomes words with NVIDIA's Parakeet v3, run locally:
  Marver asks before the one 488 MB download, and the audio never leaves your machine or touches
  the disk. Where the speech engine cannot install, captures keep typed notes.
- **Captures name themselves.** With Claude Code, each capture gets a few-word name as soon as its
  words are in, from Claude Haiku through your own login - a draft's words go to Anthropic for
  this. A name you give wins; `jam: { names: false }` turns it off.
- **Every element knows its source.** In `marver dev`, design elements carry `data-mv-loc` - the
  file and line they were written at - so your agent goes straight to the code you pointed at
  (`jam: { loc: false }` turns it off; never in a published build).

### Changed

- **Only a tag starts work** ([#5](https://github.com/TNEP4/marver/issues/5)). A plain reply in a
  thread - even one answering Marver - is conversation and starts nothing; `npx marver marks`
  lists it under "answered by you" for your chat agent. Each tag is a card answered in its own
  thread, with the thread as it stood when you sent it.
- **One job per frame.** Your agent still works on up to `jam.concurrency` jobs at once, but never
  two on the same frame, and a job's results are posted before anything new starts. A job edits
  only the frames it was given; one that needs a shared file (a kit, a layout) comes back to run
  alone.
- **One canvas per folder** ([#19](https://github.com/TNEP4/marver/issues/19)). A second `marver dev`
  in the same folder stops with "a canvas already runs here" and its link, instead of taking over
  the first one's record.

### Fixed

- **Marver's notes and replies stay on your machine when you publish.** The docs always said so, and
  `marver comments sync` never pushed them, but `marver build` copied each board's whole comment log
  into the published canvas. Now a build ships only people's threads: a note Marver pinned, its
  replies in your threads, and every capture's thread stay local.
- **An agent in a sandbox still looks at its work.** Codex runs with the network blocked, so
  `marver shot` could not reach the canvas and it replied that it could not check the render; the
  instructions now send it to the request file, which works in every sandbox.

### Upgrading

`npm install @marver-design/marver@latest`, then `npx marver init` to refresh the agent
instructions. On its first boot `marver dev` upgrades the jam journal and says what changed; a
job that was running under 0.25 shows as failed with Retry. Replies you made before the upgrade
are listed by `npx marver marks` as "earlier, maybe handled".

## 0.25.1 - 2026-10-17

### Fixed

- **Comments send at once again on canvases full of glass and animation** ([#23](https://github.com/TNEP4/marver/issues/23)).
  While you work, `marver dev` prepares a still copy of each frame with blur effects so resting
  frames cost nothing. A frame with a looping animation (a spinner, a pulsing dot) never held
  still, so its copy failed every time, was asked for again on every rest, and each ask kept a
  connection open. The browser only opens six per site, so comment sends and board saves waited
  behind them, sometimes for minutes. Now a frame with a looping animation simply rests paused
  with no copy, a copy that cannot be made is not tried again until the frame changes, and the
  canvas never waits more than 2.5 s for one.

## 0.25.0 - 2026-10-15

### Added

- **Edits land calmly.** When a file changes, the canvas reloads only the frames that read it - a
  few at a time, the ones on screen first. A frame off screen waits until you scroll near it; one
  you are using (typing in it, a laser, a comment) waits until you are done. A content frame keeps
  its height while it reloads, so the rows below stay still, and the board moves once if heights
  did change. The canvas page itself never reloads for a design edit. `npx marver perf` shows what
  each edit reached and reloaded ([Edits land calmly](docs/boards-and-folders.md#edits-land-calmly)).
- **Comments sit on what they are about.** Every note your agent pins names an element - words it
  shows (`--on`) or a selector (`--at`) - and is checked against the rendered frame while
  `marver dev` runs. Markers never cover each other and stay put while you work; a follow-up goes
  into its thread (`comments reply`, `comments new --thread`), and `npx marver comments move` re-pins
  one ([Notes from your chat agent](docs/live-jam.md#notes-from-your-chat-agent)).
- **`npx marver marks`** prints what you have not reviewed yet - the frames waiting on you, the
  ones that ask first, then the frames new since you looked - for you, or for your agent at the
  start of a session.
- **`npx marver boards pin <board> <scene/frame ...>`** puts frames on a board. A frame on no
  board is listed under **Not on a board** in the sidebar, and `work done` says where it belongs.

### Changed

- **No more All Scenes.** The built-in board that held every frame is gone - it was heavy, slow
  to open, and always marked. Every frame lives on the board it belongs to; a fresh canvas lands on
  a `welcome` board; old All Scenes links open a real board, and a canvas that published it keeps
  its threads ([Every frame on a board](docs/boards-and-folders.md#every-frame-on-a-board)).
- **Marks are exact.** They start when `marver dev` starts, so what your agent makes before you open
  the canvas is new when you do. A file every frame reads - a kit, a spec's markdown, a layout -
  lights every frame that reads it, even when it changed while dev was off. A look clears only the
  version on screen, and a frame you opened while its new version loaded clears once it is up.
  Orange now reads "waiting on you": a question comes first for `u` and keeps its own notice,
  because the agent says when a reply asks
  ([What is new, what needs you](docs/boards-and-folders.md#what-is-new-what-needs-you)).
- **What agents are told.** Pin each point on its element, one thread per topic, `--ask` on a reply
  that asks, `npx marver marks` at the start of a session, and every frame on its board.
  Upgrading: `npx marver init` updates the instructions.

### Fixed

- 0.24 counted everything an agent did before you first opened the canvas as already seen.
- Notes pinned without an element all landed on one spot of the frame, one on top of the other.

## 0.24.0 - 2026-10-14

### Added

- **The sidebar shows where to look.** A frame that changed since you looked turns blue - icon,
  title and a dot - in the sidebar and on its title above the card; one where Marver asked you
  something turns orange, with a bubble holding how many questions are open, hollow once you have
  answered, gone when the thread is resolved. Every row keeps the one item at its right edge it has
  today, and what matters most takes it, so nothing shifts or truncates further: a board you are not
  on turns blue or wears the bubble in place of its status, a closed folder or folded scene turns its
  count blue or shows the bubble. Selecting a frame, opening it from the sidebar, a link, focus or
  play, two seconds on screen at a readable zoom, or **Mark all as seen** on a scene, board or folder clears
  it. `u` goes to the next frame that needs you, then the next new one. A change is the frame's
  file or sticky note changing, a `git pull`, or an agent's `npx marver work done`; the day you
  upgrade, everything already there counts as seen. Marks are kept in `design/.local/seen.json` on
  your machine ([What is new, what needs you](docs/boards-and-folders.md#what-is-new-what-needs-you)).

### Changed

- **One notice per round.** Marver's replies on a board fold into one notice that counts them
  ("directions · 4 replies") instead of a stack of eight, and View walks through them one by one; a
  new note, or a reply that asks a question, still raises its own.

## 0.23.1 - 2026-10-14

### Fixed

- **A board file that is not JSON says why.** One stray character used to leave only `could not
  load "<board>" - staying on <board>`, while `marver boards` listed it as fine. Now the parser's
  own words, with the line and column, appear in four places:
  - a red mark on the board's sidebar row;
  - the toast;
  - the dev server's log;
  - a `(invalid JSON: …)` note on the board's line in `marver boards`.
  (#6)
- **Folders inside a scene that start with `_` stay off the canvas.** Files in a folder such as
  `_snapshot/` (the iterate guide's frozen copies) were registered as frames, shown on all scenes,
  and shot as frames with no default export. Inside a scene, a `_` now marks infrastructure for a
  folder as it already did for a file; a scene's own folder name is unaffected. (#8)
- **Tables in a wide `Doc` use its width.** Every `Md` was held to a 72-character measure, so a
  comparison table in `<Doc layout="wide">` wrapped into a tall, half-empty column. In a wide Doc,
  prose keeps that measure and a table grows as far as its cells need, up to the Doc's width. (#12)
- **HTML comments stay invisible in markdown.** `Md` and sticky notes printed `<!-- ... -->` as
  text, as on a start board's index around its generated table. Comments are now dropped; any other
  raw HTML still shows as plain text. (#15)
- **An empty phase scene waits quietly.** A feature board names its lo-fi and hi-fi scenes before
  they hold a frame, and the canvas warned `unknown scene ... skipped` on every render, toast
  included. A scene with a brief and no frames is now known, and the layout passes over it and its
  spacer; a misspelt name still warns. (#18)
- **Re-running `init` keeps the project's name.** `npx marver init` on an existing project rewrote
  `design/manifest.json`'s project line to the folder name and dropped its description, until the
  next `dev`. It now keeps the line it finds. (#13)
- **No theme warning where no theme is needed.** A canvas made only of content frames (`Doc`, `Md`,
  `Diagram`) brings its own styling, but every boot warned "no theme configured" with a banner. The
  warning now waits for a frame that needs the app's styles. (#4)

## 0.23.0 - 2026-10-06

### Added

- **A link that lands on the work.** `npx marver link <scene/frame | scene ...>` prints the canvas
  link for those frames: the board they sit on, in canvas mode, with them selected and in view - not
  the full-screen focus view. `npx marver work done` prints it for the frames it clears, and the
  AGENTS contract has every reply that created or changed frames end with it, so on a board of fifty
  frames you click once and you are looking at the change. Agents used to know only the bare board
  link, or improvise a focus link that had no way back to the canvas; asked to change a form, Claude
  Code and Codex now both end with the link to the frames they touched. Links read
  `#/b/<board>?f=<scene/frame>` or `?s=<scene>` ([Boards and folders](docs/boards-and-folders.md#links-to-frames)).
- **Your agent leaves notes where it needs you.** `npx marver comments new <scene/frame> --body "..."`
  pins a note on a frame, or on the element showing the words given with `--on`. The contract keeps
  it for what needs you - a question or a decision about that frame, a judgment call it took, a change
  you would not spot - never a changelog: asked to restyle a form, Claude Code left its one open
  question as a note on the wireframe it had not touched. Notes post as Marver and raise the bottom-right pill with a ping; reply in one and it is
  a Live Jam job, no tag needed ([Live Jam](docs/live-jam.md#notes-from-your-chat-agent)). Notes stay
  on your machine for now, like Live Jam's replies.
- **Building - the stretch between design and shipped.** Feature and project boards gain a status
  between In progress and Done: the design is agreed, the code is underway - the code glyph in
  Marver's blue (yellow is being shaped, blue is being built, green is shipped). In progress could not
  tell drawing the hi-fi from writing the code, the longest stretch of all. With `context/` it is
  read from the open plan, `stage: build`: the agent writes it as it starts implementing, and the
  sidebar's Change status picker writes it too (In progress takes it back off; no plan, and the
  picker says Building needs one). Without `context/` it is set on the board like In progress. Done
  still comes only from the shipped record ([Boards and folders](docs/boards-and-folders.md#status)).
- **The sidebar shows an agent at work.** While an agent works on a board's frames (`marver work
  start`, or a Live Jam job), the board's icon turns blue with a highlight sweeping across
  it - the frames' working shimmer in miniature - and so does a closed folder holding it, at either
  level, so something cooking is never hidden. Nobody sets it: it lasts exactly as long as the work.

### Changed

- **Boards open at their final size.** A content frame - a `Doc` of markdown, diagrams and images -
  used to open at a guess, three quarters of its width, and grow as it loaded; every growth re-flowed
  the rows below it, so a board of specs swam for seconds (on one 36-frame board, 44 layout changes
  over the first 2.7 s). The height each Doc measures at its own width is now kept in
  `design/boards/_sizes.json`, which `marver dev` writes and you commit with the rest of `design/`:
  the board opens with every frame at its real size, the content fills in, and nothing moves.
  `marver build` ships the heights of the published frames, so a published canvas opens still too.
  See [Boards and folders](docs/boards-and-folders.md#sizes).
- **A Doc reports its height once it is done** - fonts, diagrams and images loaded - instead of first
  half-loaded and again when complete. An image still loading off-screen may grow a frame, never
  shrink it under the height it is known to have.
- **The frame you are looking at stays put.** When content does change the layout - an agent makes a
  doc in the row above taller - the canvas moves around the selected frame, or the one in the middle
  of the view, instead of moving it out from under you.
- **An agent's reply to your comment comes from Marver.** `comments reply` on a thread you started
  now posts as Marver; it posted in your own name, so it read as if you had written it, and raised
  nothing. The thread stays open: you review the change on the canvas and resolve it - a resolved
  thread leaves the canvas, and the reply with it. A collaborator's thread keeps your voice, the one
  that reaches them on the published canvas, and is resolved with `--addressed-in` as before.
- **Comments written outside the canvas appear at once** - an agent's note or reply, a sync from
  the published canvas, a merge - instead of on the next 30-second poll.
- Marver's replies ping, as a person's do. Live Jam's opening "On it" line stays silent.
- A Live Jam job on a frame a chat agent has lit (`marver work start`) waits for it, so two agents
  never edit one file at once.
- A focus link (`#/f/<frame>`) opened on your dev canvas keeps its way back to the canvas (the grid
  button, or Esc). On a published canvas it is still a page of its own.
- **An agent keeps a board's status true while it works.** Lighting frames showed the work, but the
  board could still read Backlog while an agent built on it. The AGENTS contract's "Show the work"
  gains a step - the glow says someone is on it now, the status says where it stands when nobody is:
  with `context/`, an open plan naming the capability (In progress), `stage: build` once the code
  starts (Building) - and `npx marver work start` names any board it lights that still reads Backlog
  or To do, with what makes it true. Asked to start designing a Backlog feature, Claude Code and
  Codex both wrote its plan, and the board read In progress before they handed it back.
- **Status tooltips are the canvas's own.** Hovering a board's status opens the same tooltip as the
  toolbar - the status in bold, each piece of evidence beneath - instead of the browser's.
- **A tab names its canvas.** A canvas tab reads "Start here - Acme Studio" - the board, then the
  canvas, as the sidebar heads it - where every tab said "- Marver", so a row of canvas tabs now
  says which project each one is. Published canvases too.

### Fixed

- Live Jam no longer turns an untagged reply you wrote before a thread reached Marver into a job once
  Marver answers it - a follow-up is one written after Marver joined the conversation.
- `instructions/jam.md` named `comments list [<board>]`; the flag is `--board <board>`.

Upgrading: `npx marver init` refreshes the instructions your agent reads. `design/boards/_sizes.json`
appears the first time a board of Docs settles in `marver dev` - commit it with the rest of `design/`.
It is machine-written: a merge conflict in it is safe to resolve either way (until it is, `marver dev`
leaves the file alone and says so).

## 0.22.1 - 2026-10-06

### Changed

- **A project without `context/` hears about it.** The AGENTS contract opens with it: in a
  repository with no `context/`, every reply in which an agent made, specced or changed a feature or
  project board ends with one line - every feature board reads Backlog, nothing records what shipped,
  want me to set it up? - until the human answers; a no stands for the session, and nothing is set up
  unasked. `instructions/boards.md`, `npx marver boards`, `npx marver boards new` (feature, project),
  `npx marver init` and `marver dev` at boot point at it. In 0.22.0 a routing row merely pointed at
  the instruction: Claude Code and Codex, asked to spec a feature, both read it and never mentioned
  it; with the line, both end their reply with it.
- `npx marver init` on an existing canvas no longer ends with the first-session hand-off - an
  upgrade is not a first session.

### Docs

- **"Set up our context" is the whole ask.** `instructions/context.md`'s setup is now the full recipe,
  in order: the kind (`product` or `knowledge`), the draft from evidence, the canvas reading it -
  typed folders, feature boards named after their capability, a start board - and the check in ci.
  After upgrading (`npx marver init`), tell your agent: "Set up our context."

## 0.22.0 - 2026-10-06

### Added

- **Context.** `npx marver context init` gives a repository `context/`: an index any agent reads first,
  `shipped.md` - the only place availability is written, every claim `confirmed`, `reported` or
  `unknown` with a citation - one current contract per capability, a map of which code each capability
  lives in, a feedback inbox, and two playbooks Marver maintains (`reorganize-context`,
  `publish-canvas`). The root `AGENTS.md` gets one line routing every agent to the index.
- **`npx marver context check`** keeps it true, in ci or by hand: no availability or status line in a
  contract, no "section 20 wins", a level and a citation on every evidence cell, links and `path:line`
  citations that resolve, the index under 800 words and equal to the map, `restricted` files out of
  git and `team` files off published boards, feedback closed only on a confirmed deploy, no
  `"status": "done"` on a board - and on a pull request, a contract change with every change to a
  contracted capability's code, or `no-contract-change: <capability> - <why>` in the body. Exit 0
  pass, 1 fail, 2 cannot determine. `npx marver context index` regenerates the index's table.
- **Board types.** Every board wears an icon for what it is for - `start`, `feature`, `surface`,
  `project`, `feedback`, `context`, `deck`, `archive` - stated on the board or inherited from its
  folder (`"type"` on a folder's entry in `_folders.json`), then the folder's parent.
- **Status, read from evidence.** Feature and project boards wear a status in the sidebar - Backlog,
  To do, In progress (filling by phase: spec, lo-fi, hi-fi), Done, Done reported, Unknown - read from
  `context/`, or decided on the board: archived, paused, blocked with a reason. Done is never set by
  hand. The tooltip says what decided it; a change to the files reaches the sidebar without a reload.
  An open status is an outline in its colour; a settled one is filled - Done green, Archived a box.
  Right-click a feature or project board, **Change status…**: a Linear-style picker that offers only
  what a person decides - Blocked (it asks why), Paused, Archived, Back to the evidence - and shows
  what the evidence says; never Done.
  `npx marver boards` and the manifest carry types and statuses too.
- **Starting points.** `npx marver init --kind product|knowledge` gives a fresh canvas the typed
  folders every canvas shares: Start here, Features and Surfaces or Projects, Feedback, Context,
  Archive. `npx marver folders add <module>` adds one later. `npx marver boards new <name>` makes a
  board in its type's starting layout - a feature's spec, lo-fi and hi-fi bands, a start board
  rendering `context/INDEX.md` and `context/shipped.md`, a deck on its title slide.
- **`"showStatus": true`** on a `publish.json` row shows a board's status on the published canvas -
  only Backlog to Done, only when the evidence behind it is publishable (`audience: publishable` under
  `context/`; a scene brief's phase counts unless the brief says otherwise - it ships with its board),
  never a blocked reason or the evidence itself, with the date it was read.
- **Knowledge work.** `npx marver context init --kind knowledge` keeps a delivered record - Project
  and Delivered columns - and project boards read Done from it. A repository without a canvas gets
  the conventions as `context/README.md`.

### Changed

- **A published board never carries its `status`, `reason` or `capability`,** and the build fails if
  one would - or if a published status or meta carries anything beyond what is allowed. A board's type
  suggests how it publishes (a deck as `slides`, a context board as `refs`, a project as `doc`) as a
  note in the build; a publish row keeps presenting the way it always has until it names a `type`.
- **A fresh `npx marver init` creates typed folders** - product ones when an app is detected,
  knowledge ones otherwise, said out loud. On a canvas that already has boards or folders, init adds
  them only with `--kind`, and never renames or moves one.
- The board autosave keeps `type`, `capability`, `status` and `reason` from disk like `title` and
  `description`, and a folder drag keeps a folder's `type`.

### Fixed

- **Nested sidebar rows line up.** A board or sub-folder's icon now starts exactly where its folder's
  name starts, at both levels, with one icon-to-name gap throughout - 0.21.0's indent left a folder's
  boards 2px short of that line and a sub-folder's boards 6px past it. Drop seams follow the rows.
- **Renaming the open board after an agent edited it works.** The rename retried with the canvas's
  old copy of the file and failed again; it now reloads the board and retries once - and only when
  nothing was edited, dragged or switched while the request was out, so a reload never lands over
  your own change.

### Docs

- A new guide, [docs/context.md](docs/context.md): the files, the evidence levels, the check and its
  ci step, statuses on the canvas, audiences. [Boards and folders](docs/boards-and-folders.md) gains
  types, status and starting points; [Sharing](docs/sharing.md) documents `showStatus` and the
  proposed publish type; the README links it all.
- A new managed instruction, `instructions/context.md`, routed from the AGENTS contract: what to read
  at session start, when a contract changes, the setup interview when there is no `context/`.
  `instructions/boards.md` teaches types, status and the new commands.

### Upgrading

- Run `npx marver init` to take the new instructions (unedited files update in place; edited ones are
  staged in `design/.local/latest/`). Existing canvases keep their sidebar; `--kind` adds the typed
  folders when you want them.
- A board that says `"status": "done"` now fails `marver context check` - remove it; Done comes from
  `context/shipped.md`.
- Folder registry writes now take a short lock, `design/boards/.folders.lock`, so the sidebar, `folders
  add` and `init --kind` never overwrite one another; `npx marver init` adds it to `design/.gitignore`.

## 0.21.0 - 2026-10-05

### Added

- **Folders in folders.** A folder can now hold folders, one level down, so the sidebar has two
  levels: a board sits at the root, in a folder, or in a sub-folder. Every folder move works at both
  levels, from the sidebar and from the files - **New folder inside** on a top-level folder's menu,
  **Move to top level** on a sub-folder, a board dragged onto a sub-folder or between its boards, a
  folder with no sub-folders dragged into a top-level folder. At the bottom of a folder, where one
  gap belongs to several levels, the seam is indented with the level a release lands in and the
  pointer's indent picks it. Deleting a folder moves what it held up one level, into its place -
  never a board lost.
- **One new field carries it.** A sub-folder's entry in `design/boards/_folders.json` names its
  `"parent"`; a board's `folder` stays the one folder it sits in directly, and a sub-folder keeps its
  title and agent-facing description like any folder. `npx marver boards` prints the nested tree, the
  manifest lists each folder's `parent`, and a published canvas keeps the nesting of its published
  boards - a folder with nothing published at any depth stays out of the bundle.

### Changed

- **Move to new folder** makes the folder at the board's own level: a sub-folder in the board's slot
  when the board sits in a folder, right after its sub-folder when it sits in one. At the root it
  behaves as before.

### Docs

- A new guide, [docs/boards-and-folders.md](docs/boards-and-folders.md): the sidebar moves, the two
  files, descriptions, what publishing shows, mixed-version teams. The README links it and describes
  two levels. `instructions/boards.md` and the AGENTS contract teach agents the two-level moves,
  including renaming a folder slug (its sub-folders' `parent` moves with it) and deleting one.

### Upgrading

- **The registry says `"version": 2` while any folder nests, and `1` when none does.** Marver 0.20
  and earlier refuse a version-2 registry with an error instead of rewriting it flat, so upgrade the
  whole team before nesting a folder. A browser tab opened before the upgrade is refused the same way
  once folders nest - reload it.
- Run `npx marver init` to take the new folders guidance (unedited instruction files update in
  place; edited ones are staged in `design/.local/latest/`).

## 0.20.0 - 2026-10-01

### Changed

- **A slide is any frame with `slide: true` - nothing else.** The slide type keeps everything
  a deck needs around the frame: the badge, the board's reading order as the deck order, slides
  mode, publishing as a deck, comments and laser in play. What goes inside is the author's own
  code: any layout, typeface, drawing or animation. `<Slide>` is now an optional wrapper that
  fills the frame. **Breaking for decks built on it:** it no longer pads the stage, centres the
  content, sets the `sl-*` type sizes, freezes animation at rest or outlines an overflow, and
  the `sl-*` classes carry no styles - such a deck still plays, and needs its own styles to look
  as it did.
- **The host scales the stage, not the slide.** A slide never reflows. Slides mode renders each
  slide at its stage and scales the whole stage to the window, up as well as down - a projector
  shows the deck at full size without the presenter picking Fill (the Slide device never went
  past 100% before); Fill window now fits the same stage edge to edge, and slides mode offers no
  viewport presets. A slide frame met in present or focus plays the same way - a device preset
  never reflows it. A canvas node resized away from the stage shows it scaled and centred, like
  a thumbnail, with comment pins mapped through the same fit; published sleep textures are
  baked at the stage.
- **A deck chooses its stage.** A slide's stage is the `viewport` it declares, when the project
  defines it - `viewport: 'laptop'` makes a 16:10 deck at 1280×800 - else 1280×720. The canvas,
  `marver shot`, copy as image and slides mode all use it.
- **The slides guidance teaches instead of ruling.** `instructions/slides.md` drops the fixed
  type roles, margins, bands, spacing scale, pacing quotas, recipe budgets and the defect
  gate. In their place: how a slide plays and animates, the deck kit a strong deck is built on
  (a master shell, whole-slide tones, the brand's type, hairlines and labels, a drawing
  helper), ten craft habits distilled from the best decks built on marver, the method (the
  answer first, a slide list that tells the argument, a `_brief.md`, an Aim / Say / Visual /
  Source note per slide) and a review that squints at the contact sheet.
  `reference/deck-layouts.md` becomes an idea bank, with the compositions of a strong
  consulting deck described one by one. A new project's `design/slides.md` opens with a deck
  look shaped the same way. Existing projects keep their `design/slides.md`; `marver init`
  updates unedited shipped instructions and stages edited ones in `design/.local/latest/`.
- **Docs.** [docs/slides.md](docs/slides.md) and the README's Slides section describe the new
  model (a slide is code; the host scales the stage; motion hooks; the deck kit), with a section
  for decks built before 0.20. [docs/sticky-notes.md](docs/sticky-notes.md) shows a note beside a
  slide as the presenter's script - Aim / Say / Visual / Source context - and that published notes
  are readable by viewers.

### Added

- **Motion hooks for any slide.** While a deck plays, the stage marks `data-sl-play` on
  `<html>`, `data-sl-entered` once each slide has arrived, and `data-mv-slide` while the
  mounted frame is a slide, so a slide's own CSS or JS animation runs when it arrives and the
  canvas, `marver shot` and thumbnails show the finished slide. `useSlidePlay()` is exported from
  `/content` for React. The `data-animate` entrance shortcuts and the `--marver-slide-tempo`
  duration now work on any slide, wrapper or not, and every slide document shares one baseline
  (no body margin) in every host, so its geometry never depends on what played before it.
- **`Chart` and `Img` know a slide frame without the wrapper.** Labels take the stage scale and
  images skip the canvas's decoded-to-size path, so a slide scaled up on a projector stays sharp.
  `Chart` also reads `--marver-slide-accent`.

### Upgrading

- Run `npx marver init` to take the new slides guidance (unedited instruction files update in
  place; edited ones are staged in `design/.local/latest/` for your agent to merge).
- A deck built on `<Slide>` and the `sl-*` classes keeps playing but loses its padding, centring
  and type sizes. Ask your agent to give it a deck kit (instructions/slides.md describes one), or
  stay on 0.19 until you do.
- A deck of ordinary frames becomes a slide deck by adding `slide: true` to each frame's meta -
  keep its `viewport` if it was designed at one (a 1280×800 deck stays 16:10) - and setting its
  publish row to `"type": "slides"`.

## 0.19.2 - 2026-09-09

### Fixed

- **A note longer than its frame gets its room below.** 0.19.1 reserved a note's width beside its
  frame and nothing under it: a long note ran on below the card and over the next row's notes and
  frames. The column's height is now measured as it renders (markdown, fonts and diagrams decide
  it) and fed to the layout: a composed board's next row starts under the note, the gutter still
  the card's, and a board already saved re-applies its recipe when a note lands or grows past its
  frame, as it did for width. Two columns running into each other count as cramped too; the empty
  canvas under a card beside a long column is free. Leaving a device view re-checks the room the
  restored rows have. Folding a note keeps its room, so a fold never moves the board.

## 0.19.1 - 2026-09-08

### Fixed

- **A note landing on a composed board makes its own room.** 0.19.0 reserved a note's width only
  when tidy ran; a note file added to a board that already had saved positions stood on its left
  neighbour until someone pressed `t`. A board with a recipe (or the auto board) now re-applies
  its layout when a note has no room - as the file lands while the board is open, and at load
  when it landed while the board was closed - and saves the result. Boards dragged by hand keep
  their positions, as before. A deleted frame's card counts as an obstacle; a drag inside the
  reflow's debounce is never overwritten. The agent instructions say it plainly: placement is
  the canvas's job, write the file.

## 0.19.0 - 2026-09-08

### Added

- **Sticky notes.** A markdown file beside a frame (`cart.note.md` next to `cart.tsx`, `.jsx` or
  `.html`) or a scene (`_note.md` in the scene directory) renders as a yellow note left of the
  frame on the canvas - the scene's on the scene's first frame of the board, above the frame's
  own. Markdown with the Md block's rules (`goto:` links jump to a frame, images from
  `design/assets/`, raw HTML inert) and ` ```mermaid ` fences drawn hand-drawn. Comments pin on a
  note's elements as on a frame's; a folded note parks its pins on its tab. Tidy keeps room for
  notes. Every viewer folds a note at its corner and hides all with `N`; the choice stays in the
  browser, never in the board file. Published and shared canvases carry the notes, their images
  copied like any Md image. An edit to a note file updates the sticky in place; the frame is never
  reloaded. Every diagram family wears the note's look - flowchart, sequence, state, class, ER,
  pie, mindmap, timeline, gantt, journey, quadrant, git graph, block: hand-sketched boxes, one
  yellow palette, handwriting labels (the Diagram block in content frames keeps its own theme).

### Changed

- The manifest carries `note` on frames and scenes; the dev watcher regenerates it when a note
  file changes.
- The agent contract (`design/AGENTS.md`, refreshed by `npx marver init`) and
  `instructions/shape.md` teach sticky notes: what one is, when to write one, what it supports
  (markdown, tables, `goto:` links, images, hand-drawn mermaid) and how it works.
- Markdown in content frames: text inside a raw `<script>`/`<style>` block is now escaped like
  every other text, and the rendered HTML passes a tag and attribute allowlist before insertion.
  Diagram source is judged after decoding escapes; image shapes and directives are refused.

## 0.18.0 - 2026-09-07

### Changed

- **Hi-fi frames at rest sleep in place.** A frame on the canvas is one live document, awake
  or asleep - the DOM-snapshot "lean" cover of earlier releases is gone. At rest, its CSS
  animations pause and every `backdrop-filter` element (the glass that made a 4-frame hi-fi
  board checkerboard at 20-70 % zoom) wears a static texture of its own filtered backdrop,
  computed and certified pixel by pixel by the dev server in headless Chrome, under
  `backdrop-filter: none` and a static `filter` (the containing block stays, the compositor
  layer goes: a sleeping frame is one layer to raster, not thirty). Interact mode wakes the
  frame by removing one `<style>`; laser, comment pins and selection work on the sleeping
  document as it is. Nothing is copied, so nothing can shift at the transition: measured on
  real frames in a window at 200 % zoom, 29 pixels of 5.2 million differ from the live paint
  by more than 8 levels, none by more than 32. During a pan or a zoom the presented frames
  stay whole where the live board leaves the frame body blank. The one residual: at a zoom
  that puts a glass element on fractional device pixels, Chrome resamples the live effect
  layer and paints the sleeping element at its true position, so its edge rows can differ by
  up to 32 levels at the wake.
  Markdown, image, slide and lo-fi frames have nothing to compile and never ask the server.
- Theme flips and resizes wake the frame first and sleep it again once it has settled at the
  new theme or size; an edit (HMR) or a reload does the same under a new source generation, so
  a texture can never outlive the source it describes.

- **Boards open in seconds, not minutes.** A board of 128 lo-fi frames went from 77-95 s to
  under 8 s to fully ready, and its first frames show within the first second. Three causes,
  three fixes: every frame evaluated the WHOLE prebundled icon package its scene imported one
  icon from (`@phosphor-icons/react`: 3000 icons, 6.5 MB of JavaScript, ~400 ms per frame,
  the entire boot of a lo-fi frame) - the dev server now unrolls icon barrel imports in design
  sources to the per-icon modules the installed package's own barrel names (phosphor, lucide),
  one line for one line;
  all frames booted at once on one main thread and finished together, so nothing showed until
  the last was done - frames are now admitted a few at a time, nearest the centre of the view
  first; and the 10 s ready watchdog fired on every frame of a big board and renavigated it, so
  every frame loaded twice - it now counts from admission. A frame reports ready when React
  has committed, not when it was asked to render.

### Added

- **Published canvases rest under the same certified glass.** `marver build` compiles every
  published node's textures, in every theme, against the site it just built, and ships them with
  it (`__mv/bakes/`); the static shell reads one index. A shared hi-fi board now pans and zooms
  like the dev canvas (measured: 36-59 flat blocks per presented frame at worst, from 1139-1417).
  Needs Chrome on the build machine; without one the build ships without textures and says so.
  `--no-textures` / `MARVER_NO_TEXTURES=1` skip the compile.
- **Published glass was flat.** The CSS transform of a build kept only `-webkit-backdrop-filter`
  on a rule that declared both, and Chromium then computed `backdrop-filter: none`: the sidebar
  and header of every published hi-fi frame lost their blur. The build now puts the standard
  declaration back beside the prefixed one.
- **Chrome in a build container.** A root build on Linux (a Dockerfile, Railway) gets
  `--no-sandbox` and `--disable-dev-shm-usage` from marver itself; `MARVER_CHROME` still names
  a browser marver does not find. The publish guides carry a Dockerfile with Chromium.
- **Published HTML frames never reported ready.** The build shipped the frame bridge without the
  module it imports, so in a published canvas an HTML frame stayed "still loading" and neither
  slept nor took laser or comments. Both files ship now.
- `POST /__mv/api/bakes` (owner-gated) compiles frames in batch; textures are cached on disk
  under `design/.local/bakes/<generation>/` and served immutable. Identical asks share one
  compile; a compile the source outran is dropped; two dev servers on one project keep their
  own generations.

### Caveats

- Only the dev canvas compiles (it needs Chrome): published canvases sleep with the animation
  pause alone, their glass live as before.
- Glass inside glass, a glass element with a blend mode, and any frame whose paint at rest is
  not a function of its URL (random data at boot, a clock) stay live - the compiler refuses
  what it cannot certify, and `?awake=1` on the canvas URL keeps every frame live for comparison.

## 0.17.0 - 2026-09-04

### Added

- **Shots in batch.** `npx marver shot a b c`, `--scene <name>` or `--all` render many
  frames as ONE operation: one headless browser, several frames at a time inside it
  (`MARVER_SHOT_CONCURRENCY`, default up to 6 sized to the machine). `POST /api/shots`
  and the jam inbox (`{"scene":...}`, `{"frames":[...]}`, `{"all":true}`) take the same
  ask; every frame answers for itself (`results[]`, in the order asked). Measured on a
  31-frame canvas: 65 s of one-at-a-time calls becomes 8 s; a 5-frame scene, 10 s
  becomes 2 s; a single shot, 2.1 s becomes 1.05 s.
- A capture that ran out of settle budget says so: `unsettled: true` and a note, instead
  of a silently half-drawn PNG.

### Fixed

- **A shot's Chrome could outlive the server** - Ctrl-C, a closed terminal or `kill -9`
  mid-shot left a headless copy of the user's own Chrome running for ever, and on macOS
  such a ghost can swallow every link the machine opens. The browser is now driven over
  Chrome's debugging pipe, so it dies with the server however the server dies, and none
  exists between shots. The first `marver dev` after upgrading kills the ghosts and
  removes the profiles earlier versions left in the temp dir.
- Chrome starts and opens tabs several times faster: a stale `--disable-gpu` flag was
  costing ~0.5 s per start and per tab.

## 0.16.1 - 2026-09-03

### Added

- **Titles.** Boards, folders and scenes can be called anything - "MVP", "UI",
  "Checkout (v2) 🛒". Rename in the sidebar (scenes too, now) edits a `title`;
  the file name, folder key and scene directory stay the slug agents address.
  No title = the Title-Cased slug, as before. Stored on the board JSON, the
  `_folders.json` entry and the brief's YAML front matter; shown everywhere the
  object is named and carried by the manifest and `npx marver boards`.

### Fixed

- **Drops land where the seam shows.** A board grabbed by its icon and dragged
  between two folder boards landed after the folder; releases in blank space did
  nothing. The resolver now reads the pointer against the rendered rows, the
  release applies the seam on screen, and a release outside the panel cancels.
- A project reached through a symlink (macOS `/var`, a linked projects folder)
  lost its live updates; the CLI now resolves the root's real path.

### Changed

- `boards/rename` takes `{ from, to?, title?, baseHash? }` (title-only, CAS);
  new `scenes/rename { scene, title }`; `sh:scenes` relabels scenes without
  re-keying iframes.

## 0.16.0 - 2026-09-03

### Added

- **Board folders.** The sidebar's boards can live in folders, one level deep.
  Right-click the Boards header (or its `+`) for a new folder and name it
  inline - what you type becomes a slug ("Old stuff" → `old-stuff`, shown "Old
  Stuff"); right-click a board for **Move to new folder** (the folder takes the
  board's slot, the input has focus) or **Move to top level**; right-click a
  folder to **Rename** or **Delete** it (its boards go back to the top level -
  folders organise, never own). Moving into an existing folder is a **drag**:
  the board drag-and-drop now lands boards inside folders (drop on the folder
  row), in any slot inside one, back out to the root (or the left gutter of a
  folder's rows), and drags folders among boards. A click collapses a folder; the
  choice is remembered per browser. The folder holding the active board keeps
  the ancestor wash so its home stays visible collapsed.
- **Folders are files, for agents too.** `"folder": "<name>"` on a board file
  puts it in a folder (`order` ranks it among its folder siblings);
  `design/boards/_folders.json` names empty folders and ranks folders at the
  root. A folder two boards name exists without the registry. The landing
  board is the first board in sidebar order, folders included. **`npx marver
  boards`** prints the sidebar as the files say it is (folders, boards in
  reading order with their `order`, the landing board; `--json` for the tree),
  so an agent looks before it organises. The agent contract and
  `instructions/boards.md` carry the grammar, every move (create, file in,
  move out, rank, rename, delete) as a file edit, and a nudge to group
  proactively past six or eight boards.
- **Published bundles** carry the folder tree of the published boards only; a
  folder with nothing published never reaches the bundle. The published
  sidebar shows folders read-only.
- **Descriptions - purpose notes on every object, for agents.** One optional
  `description` (one sentence: what it is for, its state) on the project
  (`description` in `design/config.ts`), a board (its JSON - preserved by
  autosave and by sidebar drags like `order`/`folder`), a folder (its
  `_folders.json` entry - it rides along through renames), a scene (the first
  non-blank line of its `_brief.md`, `#` stripped, front matter skipped - no
  new file) and a frame
  (`meta.description`). `design/manifest.json` becomes the orientation file it
  was meant to be: `project`, `folders`, `boards` (sidebar order, with folder
  and description), `scenes` (with description and brief path) and `frames`
  (with description). `marver dev` regenerates it on board and brief edits too,
  and broadcasts `sh:manifest` only when the frames changed - a description
  edit never re-keys the live iframes. Published bundles ship descriptions of
  published things only (brief paths only with source revealed). `marver
  boards` prints them. Editing `description` in `design/config.ts` under `dev`
  refreshes the manifest live (the rest of the config still needs a restart).
  The agent contract teaches: write it at creation, keep it true, fix what your
  session made false before it ends (the review walk ends on it). Nothing
  renders in the canvas.
- `export const meta` picks a literal even when the prose holds the other
  quote (`"the buyer's path"`), and refuses a computed value (`"Draft" + phase`)
  instead of taking its literal half.

### Changed

- `POST /__mv/api/boards/reorder` takes the WHOLE tree (`{ tree, base }`) in
  place of `{ order }`: root boards as strings, folders as `{ folder, boards }`,
  plus the sha256 the client last saw for every board it names and for the
  registry. The server preflights every named board (present, a regular file,
  well-formed, unchanged) BEFORE writing anything - a 409 names the stale
  boards and the shell re-reads and replays its move once, so an agent's
  concurrent `folder` edit and a human's drag can never silently erase each
  other. It answers the new hashes, and the shell's autosave of the active
  board keeps its CAS token current - a reorder no longer reboots the board
  you are editing. `GET /__mv/api/boards` gains `folder`; `GET
  /__mv/api/folders` is new.
- Board enumeration (dev API, build, `--all-boards`) counts only regular files
  on the board-name grammar: `_folders.json`, temp files and symlinks are never
  boards - the build fails closed on a symlinked board. A malformed
  `_folders.json` is a 422 the sidebar toasts (and a build error), never a
  silently empty registry the next drag would overwrite.
- The sidebar re-reads its list on a coalesced `sh:boards` broadcast (any add,
  write or delete under `design/boards/`), so agent-written boards and folders
  show in under half a second instead of the 8 s poll.

## 0.15.0 - 2026-09-02

### Added

- **Copy frame as image.** The floating toolbar gains an images-square button
  (right of Copy path): one click puts the selected frame on the clipboard as
  a **2x PNG**, rendered by the dev server's headless Chrome - the same picture
  `marver shot` gives an agent. `i` is the shortcut; `⇧i` (or shift-click)
  renders at **4x** (a slide is 5120×2880). The icon breathes while the render
  runs and flashes a check on success, like Copy path. Sized to the node: a
  frame resized to Laptop copies as Laptop; content frames capture in full;
  slides are always the 1280×720 artwork. Dev canvases only - a published
  container has no browser - and one frame at a time.
- **`marver shot --scale <1-4>`** and `scale=`/`w=`/`h=`/`format=png` on
  `/api/shot`. A frame too tall for the asked scale steps down (4 → 2 → 1)
  inside a 16384px-per-side / 64M-pixel capture budget and reports it in
  `note`; the file name carries the scale actually used (`…@4x.png`), so a
  4x file always holds 4x pixels.
- **Render settle.** Every shot (not only content frames) now waits - bounded
  to 3 s, and again in the final viewport of a full-height capture - for fonts,
  in-viewport images, LOD decodes, echarts instances and mermaid diagrams before
  capturing, so a slide with a chart or a photo is never shot half-drawn. Shot
  file names: a default request keeps its unsuffixed name whatever scale the
  capture settled on; an explicit scale gets `@4x`, or `@4x-as-2x` when it had
  to step down, so nothing an agent reads moves and `@4x` never lies.

### Changed

- **Three standing rules for the agent, from dogfooding** (`AGENTS.md`,
  `boards.md`, `iterate.md`, `jam.md` - refreshed by `marver init`):
  - **One horizontal band by default.** Every curated board carries a `layout`
    recipe with the scenes side by side; a second band only when the agent can
    say why the eye should move down, with a gap that reads as "below". (Without
    a recipe the shell stacks every scene as its own row.)
  - **Look sideways.** A pin or a pasted pointer marks where the human noticed
    a problem, not the only place it lives: the agent checks the board's live
    sibling frames, fixes the same defect in the same pass and names the frames,
    or asks in-thread whether to roll it out - never one frame fixed and its
    siblings left wrong. History (`archive/`, versions) is never a sibling.
  - **Version the scene before a round.** A round of feedback on a reviewed
    scene starts with a snapshot, `design/scenes/<scene>-v<N>/`, pinned as its
    own band on the `archive` board (oldest at the top), with `data-goto`,
    `goto:` links and `meta.of` re-pointed so the version plays on its own; then
    the live frames are edited in place and threads answered. One snapshot per
    round, git commits per version on offer, staging only the round's paths.
    Rollback is a copy back; the archive is the proof of work.

### Fixed

- **Charts everywhere, not only on slides.** `Chart` now takes its ink and
  typeface from the frame it sits in (a UI screen's Tailwind colour and font, a
  Doc's tokens, a Slide's), sizes its type to the context (12px labels in a
  screen or document, 18px on a slide), paints series labels in that ink with
  no halo, follows the layout on resize (a chart no longer pins its flex/grid
  column at mount width), and keys on the option's content so a parent
  re-render never re-initialises it (a viewer's dataZoom or legend selection
  survives, and a formatter edit reaches the live chart). Before this a chart
  in a dark screen or dark spec drew dark-on-dark axis text at slide scale.
- **Video plays everywhere, not only on slides.** The player used to mount
  only under the slides-mode contract, so a `Video` in a screen, a spec or a
  published prototype was a poster forever. Now the poster is the play button
  wherever the frame is live (interact, play, focus, published); slides keep
  the auto-mounted player, and leaving interact mode on the canvas disarms a
  playing clip so the frame goes still again. New: `ratio="9 / 16"` for
  vertical clips, and `autoplay` for a muted ambient loop (an explicit choice -
  that frame stays live on the canvas). The player's glyphs are Phosphor
  (play, pause, speaker, corners). `shape.md` and `craft.md` teach it.
- **Posters render themselves.** A local clip without `poster` no longer fails
  the build: marver renders `<clip>.poster.png` beside it from the clip's own
  first moments (at 0.5 s, past the usual black opening) in the same headless
  Chrome the shot renderer uses - the dev server on first sight (the frame
  asks when its conventional poster is missing), `marver build` before assets
  are copied, and `shot` before a frame's first capture. Posters render on
  their own capture lane, so a frame's poster never waits behind the shot that
  needs it. An authored poster always wins; without Chrome the build says
  exactly which file to add.
- **A screen with a chart is still a screen.** Importing anything from
  `@marver-design/marver/content` used to turn the frame into a content
  document (spec badge, measured height, no device). Content frames are now
  those that render `Doc`, `Md`, `Diagram` or `Img`; `Chart`, `Video`, `Row`,
  `Col` and `Space` are shared blocks a screen or a slide uses freely. The
  block card (padding, hairline, surface) is a document treatment: inside a
  slide or a screen a block is bare, so charts no longer carry 32px of
  invisible padding there. `shape.md` and `craft.md` now teach `Chart`.
- **Dev server behind a symlinked path.** `marver dev` on a repo reached
  through a symlink (`/tmp` → `/private/tmp`, a linked Dropbox folder) refused
  to serve its own frames ("outside of Vite serving allow list"); the allow
  list now carries the realpath too.

## 0.14.0 - 2026-09-02

### Added

- **Slides.** A deck is a scene of `slide: true` frames: 1280×720 on the
  canvas, the slideshow badge, and a real slides mode - the standard
  prototype toolbar and walker, arrows / Space / click to advance, and
  **the board as the sorter** (the deck plays in the board's reading
  order; drag to reorder). Publish with `"type": "slides", "open":
  "slides"` plus `transition` (`fade | none`) and `chrome` (`full |
  minimal | none`); the Slide stage scales and centers itself to ANY
  viewport with pure CSS (fill window, phones, a resized canvas node -
  author px and Tailwind scale together); viewers land straight in the
  deck and the URL survives refresh. The full guide is
  [docs/slides.md](docs/slides.md).
- **The `Slide` root, `Chart`, and `Video` content primitives.** One root
  owns the stage (asymmetric margins - 88px sides, 44px top and bottom - so
  the middle band breathes; content box 1104×632), the theme tokens
  (`--marver-slide-ground/-ink/-muted` with dark twins, `-accent`, `-font`,
  `-tempo` timing both entrances and morphs), fixed type roles
  (`sl-display` 160, `sl-stat` 88, `sl-assertion` 56, `sl-support` 30,
  `sl-body` 24, `sl-caption` 18), and a development-only overflow marker
  that catches content escaping the stage, or a flex/grid child outgrowing
  its parent; `Chart`
  is Apache ECharts on a fixed supported surface (series bar, line, pie, scatter, radar, gauge, heatmap, funnel, treemap, sunburst, sankey, boxplot; SVG, lazy
  chunk, house-themed, animation stripped at rest); `Video` is
  poster-first with a glass control strip in play mode. The motion
  contract: a resting slide built from the shipped primitives serializes
  to the canvas's lean path - no canvas/video elements, no running
  animation - so a 40-slide deck pans like 40 statics (a slide that embeds
  its own canvas, video, or shadow DOM stays live, as any frame would).
- **Motion as the diff.** `view-transition-name` morphs between adjacent
  slides are the animation system; build steps are sibling frames; three
  one-shot entrance presets (`data-animate`) run after each transition
  settles. Reduced motion flattens both. Slides mode offers a 1280×720
  Slide device preset beside your devices and fill; `marver shot` renders a
  slide at 1280×720 over any authored viewport; `/content` exports
  `SLIDE_W` / `SLIDE_H`; `--marver-slide-pad-x/-y` set the stage margins.
- **The slides doctrine.** `marver init` ships
  `design/instructions/slides.md` - assertion-first argument, the type
  scale, 19 layout recipes with budgets and morph anchors, the choreography
  rules, "the space IS the design" (asymmetric margins, the 85% rule, one
  px spacing scale), seven silhouettes chosen before any recipe with a
  storyboard step and pacing rules, and a review gate that squints the
  contact sheet - with two depth references behind it:
  `reference/deck-story.md` (intake, answer-first structure, the evidence
  check, audience calibration, the writing) and `reference/deck-layouts.md`
  (the full layout atlas grouped by job, the composition grid, content
  budgets, rebuilding an existing deck, chart craft). Plus your
  project-owned `design/slides.md` - now opening with a fill-in **deck
  look** template (tokens, type, mark, colour meaning, numbers, voice) the
  agent drafts on the first deck - which overrides the doctrine and survives
  every upgrade.

### Changed

- **The play brand pill is a powered-by link** (marver.design, standard UTM
  set, `utm_content=play-brand`), sized to the pixel like the toolbar pill.
  The keyboard-hint pill is gone (two conflicting rules stretched it into a
  full-stage circle; the walker and toolbar already carry stepping and
  comment). Name your canvas - `share: { name }` - before containerising it:
  the shell's fallback is the root directory, which in a container is `app`.
- **A `slides` board plays only its `slide: true` frames.** 0.13.0 accepted
  `type: "slides"` / `open: "slides"` and played them as `present`. From
  0.14.0 the deck is the board's slide frames in reading order; non-slide
  frames on such a board warn at build, and a board with none fails the
  build with the fix in the message (a non-slides `type` plus
  `open: "present"` to keep the old behaviour, or `slide: true` on the
  frames). In the app an empty deck
  falls back to the prototype with a toast. `transition` / `chrome` are
  refused on non-slide boards. `marver init` appends `slides-inspiration/`
  to an existing `design/.gitignore`. `docs/` now ships in the package.

## 0.13.0 - 2026-09-01

### Added

- **@-mentions in comments.** Type `@` in the composer to name someone already
  visible in the canvas's comments - they get one mail for that comment and a
  bell notification on the front door. Mentions ride the same identity-minimised
  projection as authors: browsers only ever see opaque ids, and you can only
  mention people you can already see. The agent side is real too: `marver
  comments list --json` now carries each comment's mentions.
- **Reply mail.** A fresh reply mails the thread's other participants (the 10
  most recent, at most once per person per thread per 6-hour window; history
  imports never mail). Activity mail reads like a comment - who wrote it and a
  snippet of what they said (capped, escaped; the identity service holds those
  snippets for its delivery window - a disclosed tradeoff, documented in
  docs/sharing.md) - and carries an unsubscribe link that mutes email without
  touching the bell. Caveat: delivery needs Marver Sign In - a sovereign canvas
  has no relay, and `share: { notify: false }` still declines everything.
- **Mentions light up in the canvas.** A mention of you pulses its comment pin
  in accent blue until you open the thread, the marker stack opens on the
  mentioning thread first, and a mention of YOU renders as the loudest chip -
  including in your own view (they used to render plain exactly for the person
  they were for). The @-picker got a solid background.
- **In-app notifications, with sound.** A fresh mention of you - or a reply in
  a thread you are part of - raises a person-first pill while you are on the
  canvas: the author's avatar, "name mentioned you", their message, and View,
  with a soft two-tone ping (best-effort under browser autoplay rules; one
  ping per batch). Same pill family the Live Jam agent uses, so they stack
  together. History and first loads never announce.
- **Mail lands on the thread.** The activity mail's button ("Open the comment"
  / "Open the thread") deep-links straight to the conversation
  (`#/b/<board>?c=<thread>`); the relay refuses any other link shape, so mail
  can only ever point a reader back into the canvas that sent it.

### Fixed

- **Comment `profile` events now bind to the signed-in author.** They were
  accepted with an arbitrary `author.email`, which let any commenter read the
  opaque id of any guessed address off the projection.
- **Blank bodies and duplicate reply ids are refused.** Replay always discarded
  them silently; the validator now agrees, so nothing downstream (like mail)
  can fire for an event that was never going to render.

- **`marver share explain` now asks the canvas's own resolver.** It called
  `resolveAccess` locally over the fetched roster, which drops the three things only the
  server's `explain` route does - fills the owner role (a fresh owner was explained as an
  ordinary ungranted person), explains a `@domain` through a synthetic member, and marks
  the winning step. It now fetches `GET /__mv/api/share/explain?who=`, so the terminal and
  the browser dialog can never disagree. `who` stays local (it lists only granted
  non-owner principals, where a local resolve is identical).

## 0.12.0 - 2026-08-31

### Added

- **Sharing: grant people access to a canvas, person by person, from the terminal or
  the browser.** On a canvas with a persistent volume and an owner account, `marver share`
  manages a roster of *people* - who may open the canvas, who may comment, and until when -
  over the canvas's owner-only routes; the browser share dialog drives the same routes.
  `add`, `remove`, `block`, `unblock`, `general <mode>`, `list`, `requests`, `explain`, and
  `who` cover the whole surface. Exact-email grants work on a password canvas; domain grants
  (`@acme.com`), refused-visitor access requests, and the front door need Marver Sign In.
  The full guide is [docs/sharing.md](docs/sharing.md).

  **One resolver, one place.** A single pure function answers "what can this person do here" -
  blocklist first (the only deny), then the owner, then grants additive with the highest match
  winning, then a general-access floor, all clamped by each board's published ceiling. The gate
  and comment writes enforce from it, reading one `share.json`, so the policy is one thing in
  one place rather than a rule re-implemented per door. `marver share explain <email>` traces
  it for one person and `marver share who` prints the grant matrix (both convenience views -
  the dialog is the accurate read for the owner and for domain principals).

- **`design/publish.json` v2: a board can carry its artifact type and landing view, not just
  its ceiling.** A board level may now be an object - `{ "max": "read" | "comment", "type":
  "doc" | "slides" | "design" | "sketch" | "refs" | "mix", "open": "canvas" | "board" |
  "present" | "focus" | "slides", "lock": true }` - where `max` is the ceiling (the only
  field that affects access) and the rest choose how the board presents. `open` accepts all
  five view names, but slides mode is v1.5: `open: "slides"` currently lands in `present`.
  Every 0.11 canvas parses unchanged: a bare `"read"` or `"comment"` string is still a valid
  row. (This is a schema version, unrelated to the read-privacy "v2" below.) Source paths
  in a published bundle now go opaque by default (`reveal.source` defaults off) - the inlined
  manifest used to carry every frame's repo path, which is a disclosure the moment a canvas
  is shared beyond its own repo.

- **Access requests: a refused visitor can ask, and you can approve from the terminal.** When
  someone is turned away at the identity gate, the canvas offers a request form instead of a
  dead end (authenticated by a short-lived, origin-bound, single-purpose token - the refused
  visitor has no session). Requests surface in `marver share requests` and the dialog;
  approving grants canvas-wide at the role you choose, declining resolves silently. One
  pending row per address, swept after 30 days.

- **The front door at `app.marver.design`.** A signed-in home page that lists the canvases a
  person can reach, each row lit by a short summary the canvas itself signs and serves. The
  front door holds no roster and makes no access decision - it asks each canvas, and each
  canvas answers for itself, against browser-pinned keys. Keep a canvas silent there with
  `share: { frontDoor: false }` in `design/config.ts`.

### Notes

- **Read privacy is still v2.** Sharing v1 controls who gets in and who may comment; every
  admitted person can read every published board. The read boundary today is the bundle - a
  board you do not publish is not in the build. Grants are canvas-scoped and approvals are
  canvas-wide by design; `share.json` is already shaped for the per-board, per-person read
  privacy that arrives in v2, served rather than bundled.

- **First boot writes `share.json` from your live 0.11 state and changes nothing you did not
  ask for.** Every existing account gets the canvas-wide `comment` grant it already had
  (clamped per board); until that first boot, every door keeps the legacy rules. Raising a
  board's ceiling never silently re-promotes anyone granted under the old one - the roster
  ratchets down on every boot and only your explicit re-confirm raises an entry.

## 0.11.1 - 2026-08-27

### Fixed

- **The password gate's cookie now gets `Secure` from the pinned origin too.** 0.11.0 fixed
  this for the collaboration session cookie and missed the gate's own, which is set in a
  different file and is the one most likely to be sitting behind a plain `proxy_pass` - it is
  the door on every password-mode canvas. Same rule, same reason: `MARVER_PUBLIC_ORIGIN`
  decides when it is set, and `X-Forwarded-Proto` is the fallback only when there is nothing
  better. Set `MARVER_PUBLIC_ORIGIN=https://your-canvas.example.com` and the thirty-day gate
  cookie is https-only regardless of what your proxy tells the process.

  Canvases behind a proxy that does send `X-Forwarded-Proto` - Railway, Fly, Vercel, Caddy,
  and nginx configured with `proxy_set_header` - were never affected.

## 0.11.0 - 2026-08-27

### Added

- **Marver Sign In: a canvas can ask people who they are, instead of asking for a shared
  password.** Set `MARVER_ID_ISSUER=https://id.marver.design` (plus `MARVER_PUBLIC_ORIGIN`
  and `MARVER_DATA_DIR`) and the gate becomes an identity gate. People sign in once - with
  Google, or a code emailed to them - and every canvas gated this way opens without another
  password. Nobody types a canvas password, so there is none to leak, rotate, or forget, and
  revoking one person revokes exactly them. This is the better default for a team, and the
  one we run ourselves.

  **Your guest list stays yours.** The identity service proves *who somebody is* and has no
  say in *where they may go*: an address gets in if it already has an account on your canvas,
  holds an unexpired invite, or is `MARVER_OWNER_EMAIL` on a canvas with no accounts yet.
  That decision is made on your disk, and the identity service is never told the answer.
  Somebody with a perfectly valid Marver account who is not on your list gets nothing.

  **The sovereign path is unchanged and is not going anywhere.** `MARVER_PASSWORD` still
  gates a canvas with accounts that live entirely in your `MARVER_DATA_DIR`, and a served
  canvas with no `MARVER_ID_ISSUER` set makes no outbound request at all - nothing to depend
  on, nothing to phone home to. (Stated precisely, because it is the kind of promise that
  should be: `marver serve` is silent. `marver dev` still makes the one anonymous registry
  request it always has, once a day, to notice a new version - `MARVER_NO_UPDATE_CHECK=1`
  turns it off - and a workspace you have connected to a published canvas still syncs its
  comments with that canvas.) The two are alternatives rather than layers: running both
  would weaken your invite list to "an account OR whoever has the password", so the identity
  gate replaces the password gate rather than sitting beside it.

  How it works, for anyone who wants to check rather than trust: the canvas mints a
  single-use nonce bound to the browser that started the sign-in, the tab visits the identity
  service and comes back with a short-lived ES256 assertion in the URL fragment - the one
  part of a link no server ever receives - and the canvas verifies it against published JWKS
  before issuing its own ordinary session. The assertion's audience is the canvas's exact
  origin, port included, so one minted for one canvas is inert at another. The verifying half
  is dependency-free and lives in this repo (`src/server/marver-id.ts`), which is why
  pointing a canvas at a different issuer is a configuration change rather than a fork.

  `MARVER_PUBLIC_ORIGIN` is required and the canvas will not start without it, in
  development too. The audience cannot be inferred safely: nginx's documented
  `proxy_pass http://localhost:PORT` rewrites `Host` and adds no `X-Forwarded-*`, so a
  request from the internet is indistinguishable from a local one - and a canvas that
  guessed would hand its caller a `http://localhost` audience and a cookie with no Secure
  flag.

  Sign-in fails closed: if the identity service is unreachable, existing sessions keep
  working and new ones are refused. Nothing falls back to open.

  **Managing people from the repo needs `MARVER_CLI_TOKEN`.** `marver comments invite`,
  `revoke` and `sync` authenticate the CLI with a password, and an identity account has none -
  so set `MARVER_CLI_TOKEN` on the canvas to a *generated* secret of 32 characters or more
  (`openssl rand -hex 24`) and pass the same value back:

  ```
  MARVER_CLI_TOKEN='<that same value>' marver comments connect https://canvas.example.com
  ```

  (`--token` works too, but a secret on the command line is visible to anything that can
  list processes.)

  It acts as whoever owns the canvas, so it does nothing until somebody has signed in and
  claimed it. Generate it rather than choosing one: nothing rate-limits this credential and
  nothing slows a guess down, so its entropy is the whole defence, and a length floor is the
  only part of entropy a program can check. The canvas refuses to start on a value that is too
  short, and on one containing characters an `Authorization` header cannot carry - hex rather
  than base64, so that a canvas never boots holding a secret it would go on to reject.

  `connect` trades that secret for an ordinary session and stores THAT in
  `~/.marver/canvases/`, so neither the secret nor the session lands in your repo. **Rotate
  `MARVER_CLI_TOKEN` to revoke it**: every session it minted stops working the moment the
  variable changes, and sessions people hold in their browsers are untouched. That is the
  lever rather than `comments revoke`, because the session acts as the owner and a canvas
  refuses to remove its last owner.

  It is an environment variable, and not a page that hands out tokens to whoever is signed in,
  for a reason worth stating plainly: authored frames run same-origin in a canvas. That is
  deliberate and documented, and it means frame JavaScript can read `mv_c` and ride the
  viewer's session - so any browser-reachable way to mint a durable credential is a way for a
  frame to mint one silently and carry it off, an owner's if an owner is the one looking. A
  browser-approved device flow was built for exactly this job and pulled before release for
  exactly that reason; requiring a real top-level navigation narrowed it and did not close it,
  because `Sec-Fetch-Site: same-origin` proves where a request came from and never that a
  person meant it. An environment variable is on the other side of that line: it is never
  sent to a page, and reaching it already means reaching the deployment.

  The cost is honest. It is a static secret that rotates by redeploying, and it acts as the
  owner rather than as a person, so it is an operator's credential and belongs with your other
  deployment secrets. Per-member CLI credentials still want the frame isolation this release
  does not have.

### Changed

- **The gate refuses to be framed** - every gate response now carries
  `Content-Security-Policy: frame-ancestors 'none'` and `X-Frame-Options: DENY`. A
  credential form inside somebody else's page, under a transparent button, is the classic
  clickjack, and `SameSite=Lax` does not help because a framed page on the same site still
  carries its cookies. Called out because it is a behaviour change rather than an addition:
  if you were embedding a password-gated canvas in an iframe, that stops working. Embedding
  a canvas people have already signed into is unaffected - it is the gate itself that
  refuses.

### Fixed

- **`Secure` on the collaboration session cookie no longer depends on a header your proxy may
  not send.** A canvas decided whether it was on https by reading `X-Forwarded-Proto`, and
  nginx's own documented `proxy_pass http://localhost:PORT` sets no `X-Forwarded-*` at all. A
  canvas served over https behind that configuration saw no header, concluded "not secure",
  and issued a thirty-day session cookie the browser would happily send over plain http. Where
  `MARVER_PUBLIC_ORIGIN` is set it now decides - a deliberate statement by whoever deployed
  the canvas, rather than a guess about a proxy that may not be speaking. The header remains
  the fallback only where there is nothing better, which is development on loopback.

  This release fixed the collaboration session cookie only. The password gate's own cookie
  still guessed from the header - see 0.11.1.

- **The collaboration credential has moved out of your repository, because `marver dev` was
  serving it.** It lived at `design/.local/collab.json`, and the dev server puts the repository
  on the web so frames can import from it. Authored frames run same-origin, so any frame could
  `fetch('/design/.local/collab.json')` and carry off a live session for your published canvas.

  It now lives in `~/.marver/canvases/`, keyed by the project's path - one file per canvas per
  machine, outside anything that is served. `connect` writes there, `dev` moves an older
  credential out of the repo the first time it runs, and nothing needs doing by hand.

  Guarding the old location was tried first and is the reason for the move: a deny rule matched
  the path asked for rather than the file served, so a repository containing
  `leak.json -> design/.local/collab.json` walked straight past it - and after that was fixed,
  `public/` and Vite's derived `index.html` candidates each did the same. Enumerating a
  bundler's resolution rules is not a thing anyone finishes. Those guards stayed as depth,
  `design/.local` is still never served whatever route a request takes, and Vite's own default
  deny list is no longer replaced by ours.

  If you have ever run `marver dev` on a repository you did not write, treat that credential as
  exposed: change `MARVER_CLI_TOKEN` on the canvas, which ends every session it minted, or on a
  password-account canvas `marver comments revoke` and reconnect.

- **A gated canvas is no longer publicly cacheable in identity mode.** The `Cache-Control`
  decision keyed off the password verifier alone, so an identity-gated canvas marked its
  assets `public, immutable` - an invitation for a shared CDN to serve somebody's private
  frames to anybody who asked. Both modes are now `private, no-store`.

- **A missing cosmetic file no longer falls through to the bundle.** Favicon and logo paths
  are allowed past the gate on the promise that they are favicons and logos; when no such
  file existed, the hash-routing fallback handed an unauthenticated caller `index.html`
  instead. For those paths a miss is now a miss.

## 0.10.2 - 2026-08-24

### Fixed

- **`marver shot` renders content frames at their real size.** The verify-loop screenshot
  (and the file-drop `design/.local/shots/*.request.json` transport) used to capture every
  frame at the mobile viewport - a 780x1688 crop - so a `Doc layout="wide"` frame came back
  squeezed and anything past ~1688px tall was invisible to the verifying agent. A shot now
  sizes a content frame the way the canvas does: its `contentWidth` (760 document / 1280 wide,
  or a declared `meta.viewport`'s width) at full measured height. Long frames render in full;
  past a capture-safe height the shot drops to 1x pixel density and, if still enormous, reports
  `truncated` with a note rather than producing a gigapixel PNG. The `/api/shot` and file-drop
  results now include `scale` and, when clipped, `truncated`/`note`.
- **A slow dev server no longer fails a healthy frame.** A frame that hadn't reported ready
  within 10s was marked `frame failed` / `frame never reported ready (10s)`, hidden behind a red
  card that only a per-frame click could clear - but the frame was usually fine, just waiting on
  a slow module response (Vite re-optimizing dependencies, or the box saturated by parallel Live
  Jam agents). A genuine failure already reports itself immediately, so silence past the deadline
  now auto-renavigates the frame once on a fresh revision; if it's still loading it stays visible
  behind a quiet "still loading" pill (with its own reload) instead of a failure. A late ready
  clears it, and a stale ready from the superseded document is dropped by generation so it can't
  mark a reloading frame ready.

### Added

- **`marver dev` warns when your instructions predate the installed package.** Upgrading the
  package doesn't refresh the managed files in `design/` - so a workspace scaffolded on an
  older version could run the new daemon against an agent contract that predated it (for
  example, Live Jam armed with no `jam.md` on disk). Dev now prints one line at boot when a
  managed instruction file is behind the installed version - `instructions predate marver
  <version> (jam.md, ...) - run: npx marver init` - comparing the on-disk `marver:managed`
  hashes against what this version ships. Files you edited or detached are never flagged.

## 0.10.1 - 2026-08-21

### Added

- **Point an agent at anything on the canvas by its location.** Right-click a board, scene,
  or frame in the sidebar for a Copy path action (the same signpost icon as the floating
  toolbar): a board copies `board: <b>`, a scene `board: <b> - scene: <s>  (design/scenes/<s>/)`,
  a frame `board: <b> - frame: <id>  (<file>)`. Laser copy now leads with `[board > scene]`
  before the file and selector, and the floating toolbar plus Shift+P copy that same frame
  address (board, frame, file) - all routed through one helper so the three never drift. On a
  real copy the toolbar signpost flashes to a check. The AGENTS templates and the Live Jam
  guide explain how to read every pasted address.
- **Manage boards from the sidebar.** Rename a board inline from its right-click menu; the
  dev server performs an atomic no-clobber move and refuses a board that has a live connection
  or a comment log (comment and sync state is board-keyed and cannot follow a file rename).
  Reorder boards by dragging - a pointer-driven gesture (not native drag-and-drop) that holds
  a grabbing cursor for the whole drag and marks the landing with a single brand-blue seam per
  gap, overlaid so the list never shifts. A plain click still switches boards.

### Removed

- The Duplicate-frame button on the floating selection toolbar.

## 0.10.0 - 2026-08-21

### Added

- **Live Jam speaks five more agent CLIs: Cursor, droid (Factory), opencode, grok, and pi**,
  alongside claude and codex - which also covers the apps built on them (Factory drives
  `droid`, Cursor drives `cursor-agent`, Conductor drives `claude`). Each adapter spawns its
  CLI headless with the same posture claude set: edits yes, shell no (or OS-sandboxed) -
  cursor runs with its sandbox forced on and never gets `--force`, droid loses its shell,
  delegation, and connector tools, opencode runs under a per-spawn default-deny permission
  grant, grok has its shell and subagents removed, pi's tool allowlist simply omits bash. Detection knows their env markers (`CURSOR_AGENT`,
  `OPENCODE`, `PI_CODING_AGENT`; droid and grok set none and are found by PATH), and
  `jam: "droid"` in the config block names one exactly as before. The Live Jam guide carries
  the full spawn-and-jail table.

- **The verify loop: agents can now SEE what they built.** Field feedback from 0.9.0: a
  jam agent shipped variants that were blank at render time, because no-shell (deliberate -
  the job packet carries untrusted text) also meant no screenshots. The answer is a jailed
  capability, not a shell: `GET /api/shot?frame=<id>&theme=<t>` on the dev server renders
  the frame with the machine's own headless Chrome (CDP over Node's built-in WebSocket -
  zero new dependencies) and returns a PNG under `design/.local/shots/`. Two transports,
  because the no-shell jail rules out the obvious one: a **file-drop inbox** (the agent
  writes a `<slug>.request.json`, the dev server renders and writes a `<slug>.result.json`
  with the PNG path) works for every agent including Claude Code, whose WebFetch refuses
  localhost; and `npx marver shot <frame>` / `GET /api/shot` for shell-ful agents and
  humans. The inbox watcher pairs `fs.watch` with a 1s sweep, so a request lands even on
  filesystems where watching is flaky (macOS temp, network mounts) - the same belt-and-
  braces the comments daemon uses. Readiness is deterministic (root mounted, fonts ready);
  a failed navigation, an unreachable server, or a frame that threw at render all return an
  honest `{ok:false,error}` carrying the real cause (the frame's own exception, surfaced via
  the frame host) rather than a blank that reads as success - so even an agent whose model
  cannot read images still learns from the JSON whether the frame rendered. The generated
  jam instructions require: shoot, read the result, LOOK at the PNG when you can - and say
  so honestly when you cannot. Verified live: Claude Code screenshotted a tour frame through
  the file-drop path and read back its real headline; Claude, Codex, Cursor, grok, and pi
  all read a rendered PNG correctly in isolation (opencode's configured model has no vision,
  and degrades to the JSON signal).
- **A troubleshooting drill written for the agent, with an upstream loop**
  (`design/instructions/jam.md`): boot line first, then the raw run log in
  `design/.local/jam-logs/`, then the CLI's own headless auth check - fix what belongs to
  the workspace (a wrong `jam.agent`, a logged-out CLI), and file what belongs to marver
  at github.com/TNEP4/marver/issues with the evidence and, when debugging surfaced one,
  the patch. The give-up reply on the canvas now points at the same drill.

### Fixed

- **The daemon pins `PWD` to the workspace when spawning an agent.** `spawn(cwd:)` changes
  the directory but not the inherited env var, and some CLIs (opencode, verified) trust
  `PWD` over `getcwd` - a dev server whose own cwd differed from the repo root would have
  had the agent editing the wrong directory.
- **The early ack no longer leaks plan narration into the thread.** A first message like
  "On it...\n\nNow let me gather context: ..." posted the note-to-self along with the ack;
  a fenceless ack is now trimmed to its first paragraph (a fenced first message stays whole).
- **`/api/shot` is owner/token gated**, so a cross-origin page can't trigger the browser it
  spawns; the `marver shot` CLI sends the dev-session token, and the file-drop jam path is
  unaffected. It also renders from the dev server's actual listening address, not the
  client-supplied Host header. And a hung headless Chrome can no longer wedge the shot queue -
  a watchdog kills it past a deadline and settles every in-flight CDP call.
- **The working glow follows the agent to the frames it actually builds.** A comment on one
  frame whose answer is several NEW frames ("one frame per page") left the glow stuck on the
  commented frame. Jam agents have no shell to run `marver work`, so the daemon now moves the
  glow itself: it watches which frames the agent creates or edits during the job, lights those,
  and clears the commented frame once the agent is clearly building elsewhere.
- **Tighter agent jails, verified live.** grok's shell was actually reachable - its deny-list
  named `run_terminal_cmd` but the real tool is `run_terminal_command`, so the flag missed and
  a prompt-injected comment could run commands. grok now uses a read/edit tool ALLOWLIST (no
  shell, no web, no subagents - a name a deny-list can't miss). opencode runs `--pure` so a
  repo plugin can't execute outside its permission grant. Every other CLI's shell containment
  was re-checked against the real binary (Cursor's OS sandbox blocks network egress; pi and
  droid have no shell tool) rather than assumed. The Live Jam guide now states the trust model
  plainly: your own agent, on your machine, every diff reviewed - not an airtight sandbox.

## 0.9.0 - 2026-08-21

### Added

- **A Live Jam guide** (`docs/live-jam.md`), now that the feature arrives armed rather than
  opted into: how the agent is chosen and how to correct it, every key in the config block,
  what each of the two CLIs is allowed to do, where the trust boundary sits, and what to
  check when a mention does nothing.

### Changed

- **Live Jam is on by default, at concurrency 6.** Tagging `@marver` in a comment was the
  headline workflow and a config edit stood in front of it. Now it arms itself: the tool
  RUNNING the process wins (its env markers are evidence, and `init` is usually run by the
  agent), then whatever is on PATH, claude first. That last tie-break is a guess, which is
  why the answer is made visible rather than clever - `init` prints the agent it chose and
  writes it into `design/config.ts` in plain sight as
  `jam: { agent: "claude", concurrency: 6 }`, and the generated instructions have the agent
  confirm that line names the tool it actually is. One word to correct, once per repo.
  Workspaces that predate the block need no re-init; they resolve the same way at every
  dev boot. `jam: false` is the off switch, and `jam: "codex"` is shorthand for naming the
  agent. Six frames at once replaces three - at three, half of a multi-frame ask sat
  waiting on the other half while the human watched. With no agent CLI installed, jam stays
  off and both `init` and `marver dev` say so instead of going quiet.
- **A named agent is never quietly swapped, nor armed when it cannot run.** `jam.agent`
  naming something marver cannot spawn turns Live Jam off with a printed reason rather than
  detecting some other tool and answering the human's comments with it; the same applies
  when the named CLI is not on PATH, which used to claim every mention and then fail it. A
  `design/config.ts` that fails to parse also leaves jam off - it may have said `jam: false`,
  and arming a process spawn against intent we cannot read is the one wrong-way error worth
  avoiding.
- **`jam.subagents` does something now, and Codex fans out too.** The setting existed but never
  reached the spawned agent, which reads no config - so the parallel-frame policy is stated in
  the job prompt, and turning it off keeps a job on a single agent. The Codex adapter had also
  been marked as having no subagents; `codex exec` carries `collaboration.spawn_agent`, so a
  multi-frame Codex job now fans out the way a Claude Code one does. The prompt only ever says
  "you MAY", so an older CLI without those tools just works serially instead of failing.
- **Worth knowing, now that it is on by default:** the two agents are locked down differently,
  because their CLIs differ. Claude Code is spawned with shell access removed entirely
  (`--disallowedTools Bash`); Codex runs in its own `workspace-write` sandbox, which bounds
  what commands can *touch* but still lets the model run them. Both are confined to the
  workspace, and every change is a diff you review.

### Fixed

- **A one-message agent no longer posts the raw reply fence into the thread.** Live Jam posts
  the agent's first streamed message as an immediate ack. Codex emits a single message at the
  very end, carrying the completion block, and a fast Claude Code run can do the same - so the
  ack was the finished reply, fence and all, followed by a second message with the same words.
  The early path now normalizes exactly like the final one, which also makes the existing
  duplicate check catch it: one clean reply.

- **The jam ledger and journal are bound to the machine that wrote them.** Both live in
  `design/.local/`, which is gitignored and never synced - but gitignore is a convention,
  not provenance: a repo can force-add its own `.local/` and hand a clone a pre-authorized
  ledger plus a pre-baselined journal. Each line and file now carries a device stamp, so
  jam state that arrived with a clone is read as absent. The stamp is derived from the
  machine, not stored (marver writes nothing outside `design/`), so it stops one repo
  published to everyone rather than someone who already knows your machine - and the larger
  caution is unchanged either way: `marver dev` imports and executes `design/config.ts`, so
  running a dev server in a repo you do not trust is already running its code.
  One-time upgrade cost: an existing journal predates the stamp, so the first boot after
  upgrading rebaselines - any `@marver` mention left unprocessed while the server was down
  is marked seen instead of run. Re-comment to pick it up.

- **Comments wear the brand blue.** Pins, thread cards, the comment-mode pick cursor and
  the anchored-thread chrome move off systemGreen. Interact keeps purple, and green is now
  reserved for the done state alone - in dark mode the comment and done greens had drifted
  to the same value, so a frame carrying threads and a frame that had just landed a change
  looked alike. A pin, a thread card and a selected frame are told apart by shape.

## 0.8.1 - 2026-08-19

### Added

- **`marver work` - the chat agent's hand on the canvas.** The live working shimmer was
  exclusive to Live Jam; now any coding agent can drive it: create the frame files first,
  pin them on the board, `npx marver work start <scene/frame ...>` - the human sees the
  request land on the canvas in seconds, before the first component exists - build
  (independent frames in parallel, one subagent each), then `work done`. Marks are leased
  (default 10 min, max 30) so a crashed agent can never leave a frame glowing. The dev
  server writes `design/.local/dev.json` (port + per-boot token) as the CLI's discovery
  and credential; presence itself never touches disk. The generated AGENTS.md teaches
  the choreography.
- **`marver canvas` - a second name for `marver dev`.** Both start the same full local
  canvas (hot reload, comments, Live Jam, working state); `dev` reads naturally to
  developers, `canvas` to everyone else. There is no reduced mode behind either name.
- **Agents report marver bugs upstream.** The generated AGENTS.md now teaches the
  coding agent to file issues on the marver repo when the TOOL itself misbehaves
  (search first, `bug`/`enhancement` labels, version + expected-vs-actual + an
  abstract reproduction) - with privacy as hard law: issues are public, so nothing
  from the owner's repo (code, names, comment text, screenshots) may appear; failures
  are described in neutral terms or handed to the owner instead. The owner is always
  told what was filed. Every canvas becomes a field reporter, no user effort.

### Changed

- **The powered-by links carry automatic attribution.** Every canvas's marver.design link
  now ships UTM-tagged with zero setup: `utm_source` says which surface class sent the
  visitor (`published-canvas` / `dev-canvas`), `utm_medium=powered-by`, `utm_campaign` is
  the canvas's own name slugged (`marver-tour`), and `utm_content` names the placement
  (`gate` badge / `shell` wordmark).
- **`init` wires every agent in, and showing the work comes first.** The repo-root
  CLAUDE.md @-import has a sibling: init now also creates (or appends one pointer line
  to) a root AGENTS.md, so Codex-style agents inherit the canvas contract too. And the
  contract's Show-the-work section is stricter - making the request visible is the
  agent's FIRST act: skeleton frame created, pinned, and shimmering before research,
  reading the codebase, or planning begins.
- **Comments are frame-scoped now, and notifications reach you anywhere.** The client holds
  every board's comment log, not just the open board's: a thread pins to its frame wherever
  that frame appears - the all-scenes board finally shows every conversation - and a Marver
  reply landing on ANY board raises the notification pill no matter where you are, with View
  navigating to the right board and opening the thread. Replies and resolves route to the
  thread's origin log, so reading a thread from another board never forks it.

### Fixed

- **The jam shell ban is enforced, not just requested.** The Claude Code adapter now passes
  `--disallowedTools Bash` alongside its tool allowlist: `--allowedTools` only pre-approves
  tools, so a permissive inherited `settings.json` could have re-authorized shell. The
  documented boundary (no shell for untrusted comment text) is now explicit in the spawn.
- **The jam ack never narrates.** The agent's streamed first line posts to the thread
  verbatim - and sometimes that line was plan narration ("I'll start by acknowledging,
  then look at the board...") instead of a message to the owner. The packet now spells
  out that the first text ships verbatim and must address the owner, and the daemon
  backstops it: an unmistakable plan-narration first line is skipped and the next
  streamed text becomes the ack - a later tight ack, never a leaked plan.
- **`data-goto` follows a frame to its board.** Clicking a link whose target frame lives on
  another board used to SPAWN that frame onto the current board (mutating it - and in dev,
  saving the mutation). Navigation now follows the frame home: the canvas switches to the
  first curated board that pins the target, focuses it, and carries interact mode across the
  switch - links are navigation, never edits. A frame no board pins still spawns in place
  (the original single-board prototype behavior), and play mode is unchanged.
- **Comments no longer vanish across board switches and reloads.** Board nodes the file did not
  key yet were minted RANDOM keys on every load - and comments anchor to node keys, so any
  comment created on a never-saved board orphaned invisibly on the next mount (and on published
  canvases, which can never save keys back, on every visit). Keys are now deterministic
  (board + frame + occurrence), and a single thread-host resolver adopts threads whose stored
  key no longer holds onto the first node still showing their frame - a comment degrades to its
  frame, never to invisible, and never to two pins.
- **Old comment logs keep their origin.** Events written by 0.8.0 clients carry no `board`;
  they now get it stamped from the log they came from, so replying to an old thread can never
  route the reply into whatever board happens to be open.
- **Create-first frames land at their declared size.** A board node appended before the
  manifest registered its frame file was sized by the 390x844 guess - and the guess persisted.
  The size now corrects itself the moment the frame arrives, guessed sizes never reach the
  file, and authored sizes on temporarily-missing frames are never touched.
- **`marver init` no longer resurrects the demo scene.** Re-running init on a workspace with
  real scenes used to scaffold demo/ back next to real work; the demo now only lands on a
  first canvas.
- **Static canvases stop knocking.** A published canvas without collaboration used to poll
  the comments API forever (and retry an EventSource against it); the client now detects the
  static serve once and goes quiet.
- **No phantom comments on static canvases.** A published serve without `MARVER_DATA_DIR` used to
  let `/__mv/api/*` requests fall through to the static handler, which answered them with
  `index.html` HTTP 200 - the client read that as success, so a guest's comment echoed locally
  and silently evaporated on reload. The serve now refuses the API with a 404 JSON error the
  client surfaces as a toast.
- **The published shell wordmark honors `share.name`.** Deploy hosts build from anonymous paths
  (`/app`), so the sidebar read "App"; a declared `share.name` now names the shell like it
  already named the gate.

## 0.8.0 - 2026-08-19

Live Jam: tag `@marver` in a canvas comment and a local coding agent picks it up, edits the real
frame source, and replies in the thread - live. Plus a dev identity system and a full polish pass
on the comment thread experience.

### Added

- **Live Jam - the agent in the thread.** A daemon inside `marver dev` watches the comment logs:
  an owner-authored `@marver` spawns a headless agent (`jam: { agent: "claude" }` or `"codex"`)
  that reads the whole thread, edits the real frame source, and replies live - a streamed
  first-line ack within seconds (model provenance included), a look-around-before-asking clarify
  ladder, replies matched to your message's energy and length, follow-ups in an engaged thread
  triggering WITHOUT re-tagging, parallel jobs across frames, and crash-safe recovery: a batch
  killed mid-run (even by a server restart) resumes on the next boot from a durable journal.
  Every reply carries a provenance tooltip - dev user, harness, model.
- **A hard trust boundary.** Only the owner's device triggers: a device-bound ledger (keyed per
  board + comment id, never synced), a same-origin + cookie gate on every dev write (comments AND
  profile), and a recursion guard so agent replies never re-trigger. The agent runs locked down
  (Claude Code: no shell, Read/Edit/Write/Glob/Grep + WebSearch/WebFetch only; Codex: confined
  to its workspace-write sandbox) - and its reply is extracted structurally
  (the `marver-reply` block), so narration can never leak into a thread. Comment text is framed
  as untrusted data end to end.
- **The felt surface.** A frame being worked on wears the selection geometry in marver blue with
  a rotating shimmer, a top-to-bottom content wave, and a parallelogram shimmer matrix on its
  flank - phased per frame so parallel jams don't pulse in sync, held alive by a heartbeat for
  the whole job. Replies land as minimal notification pills (frame title + preview) that stack
  into a card deck at 3+, expand, clear, and jump you to the thread - delivered instantly over
  the dev websocket. Marver renders as its own participant with the blue mark avatar everywhere.
- **Dev identity + review controls.** Comments in dev render as "You" (green Y) until you set a
  profile - hover your avatar (pen on gray), "Set up your profile": name + photo, saved to
  `design/.local/` on your machine only; a connect account takes over name + email automatically,
  and account-less history re-renders as the live you. New shortcuts: ⇧L toggles "laser comment"
  (the element lighting comments paint in the artwork - anchoring stays precise with it off),
  ⇧C hides pins, both in stateful two-row tooltips; Prototype view moved beside Hide UI.

### Changed

- **The thread card grew up.** World-parked beside its frame with pin-style screen-constant
  scaling, height rules that respect the frame, content-mask scroll fades, a custom glass
  scrollbar riding the card's far edge (action buttons never collide), and a stage-docked
  position in Play that re-docks on device switches. The composer centers its text exactly,
  renders `@marver` bold WITHOUT caret drift (metrics-safe text-stroke), and the send button is
  reliably clickable.
- Laser/comment hover lighting leaves a frame together with the pointer - no fossilized outlines
  on frames the cursor crossed; the expanded notification list no longer clips pill shadows.

## 0.7.0 - 2026-08-17

Prototype mode becomes a first-class review surface. The prototype (Play) now carries the same toolbar
as the canvas, laser and comments work INSIDE it, and every comment wears the colour of the element it
points at - the groundwork for tagging a coding agent from anywhere you review.

### Added

- **The prototype is a review surface, not just a viewer.** Play's top-right toolbar is now the SAME
  controls as the canvas - device switch, theme, laser, comment - built from one shared set of
  components so the two can never drift. Laser and comment work inside the running prototype: the stage
  runs the same element inspector the canvas frames do, so you can point at, highlight, and comment on
  the live app while you walk a flow. The bottom-left navigator (restart / prev / i-of-N / next) stays.
- **Hide UI (H).** One binary toggle hides all chrome for a clean point-and-shoot frame, shared by the
  canvas and the prototype. No auto-fade, no hover magic; a page refresh always brings the chrome back
  (the safety net for a forgotten shortcut). It replaces the prototype's old three-state auto-hiding bar.
- **Comments wear their element's colour.** Comment mode reuses laser's per-element depth hue: the
  element you hover, the composer, the pin, the thread card, and the active-element highlight all take
  that specific element's colour - a comment on a blue heading reads blue, on a green button green. The
  avatar keeps the commenter's own colour; filled buttons use a hue-aware shade so the glyph stays legible.
- **The commented element lights up.** Picking an element locks a persistent outline on it (the highlight
  stops chasing the mouse while you compose), and opening a thread re-lights its anchored element - so
  everyone sees exactly which element a comment is about. It clears on close.

### Changed

- **Prototype chrome is discreet and reliable.** The prototype's floating toolbar wears the same quiet
  dark skin as the bottom-left navigator, so it recedes into the stage instead of reading as a bright
  slab; and it no longer auto-hides or sticks under the cursor - it behaves exactly like the canvas pill
  (explicit collapse, Hide-UI, no surprises).
- **Prototype is an action, not a menu item.** The Prototype-view button moved into the canvas pill's
  action group (beside comment, laser, tidy), leaving the far right purely for UI management (Hide UI,
  collapse).
- **The element label reads clearer.** The laser/comment element tooltip now sits below-left of the
  cursor with a gap - clear of the element you are pointing at - and slides in from the edge instead of
  being clipped.
- **Escape exits laser mode**, matching comment mode.

### Fixed

- **Canvas comment highlight is now reliable.** A frame hosting an open thread or a draft shows its LIVE
  app rather than the frozen lean snapshot, so the active-element highlight appears, updates, and clears
  in real time - it used to be intermittently missing, or frozen after close, depending on snapshot
  timing. A clean snapshot rebuilds once the thread closes.
- **Highlights only show while a thread is active.** Closing a thread or hiding pins (Shift+C) clears the
  element highlight; a remotely-resolved thread no longer strands one.
- **Prototype comment overlay positions faster** after a walk and never renders behind the frame or off
  screen. Element-hue values, message origins, and stage-swap timing are all validated.

## 0.6.0 - 2026-08-17

Image-heavy boards, done right. A board full of high-resolution screenshots now zooms fast and stays
crisp, images render in FULL instead of cropped, content frames size themselves to their content, and
the switcher opens on a tight landing board instead of loading every frame at once.

### Added

- **Client-side image level-of-detail (LOD).** A board of 150+ high-res screenshots used to jank hard
  on zoom - the real cost was decoded memory, not file size (a 2708x1610 PNG is ~17MB decoded, so 174 of
  them held ~3GB of bitmaps the browser resampled every frame). Each `Img` now decodes STRAIGHT to its
  on-screen size via `createImageBitmap` and paints on a canvas; bitmaps freeze during a pan/zoom and
  re-pick resolution only when the gesture settles (the tldraw pattern). Result on a 174-image board:
  ~26MB decoded at overview vs ~3GB before (~100x less), lag-free zoom, crisp detail when you stop.
  Falls back to a plain `img` where `createImageBitmap` is unavailable.
- **Board ranking and a fast landing board.** Boards carry an `"order"` field; the switcher ranks curated
  boards by it and always sinks the auto `all-scenes` everything-board to the BOTTOM. A fresh open now
  lands on the FIRST curated board - a tight, fast board and a good first impression - instead of
  rendering every frame at once. Rank boards deliberately; the first is what people see first. `order`
  survives the shell's autosaves.

### Changed

- **Reference images show in FULL.** `Img` no longer cover-crops to a fixed height (that sliced the
  sides off every screenshot). Each image fills its column at its natural aspect ratio - never cropped,
  never letterboxed - so same-aspect screenshots line up on their own and the frame auto-heights to fit.
  Size an image by how many share its `Row` (fewer = bigger), not by a fixed height; `h` is accepted for
  back-compat but no longer constrains size. A clean inset hairline (grayscale, light + dark) sits on the
  image's own edge, overriding a screenshot's ragged or baked-in border instead of framing it twice.
- **Content frames fit their content when you resize.** A manual WIDTH resize now keeps the HEIGHT auto:
  the frame reflows and refits to show everything, instead of freezing at a stale height (only an explicit
  device viewport locks it). The content-frame height cap was raised so a long reference doc renders in
  full rather than clipping, and zoom now reaches 500% for inspecting screenshot detail.
- **Authoring doctrine updated to match.** The scaffolded instructions now teach sizing images by row
  grouping instead of cropping, and ranking boards with `order` (first = landing, `all-scenes` is heavy
  and auto-last).

### Fixed

- **No jiggle on zoom.** An image's display aspect-ratio is pinned on first decode, so an LOD resolution
  switch changes only the pixels, never the layout box - frames no longer drift as you zoom.
- **Fast zoom no longer stalls frames.** The LOD re-decode is debounced past the gesture and drops queued
  work when a new gesture starts, so oscillating zoom-in/out never stacks decode waves and times frames
  out to a ready-timeout.

## 0.5.0 - 2026-08-15

The performance & fidelity release (SPEC-M5): the canvas stops jiggling. Moving around a board no
longer swaps between two documents on every pan/zoom - each passive frame renders as a lean DOM
snapshot that IS what you see, and the real live app takes over the moment you interact with it.

### Added

- **Lean-primary rendering.** Every passive frame shows a **DOM snapshot** - a self-contained static
  copy of the frame (real DOM + real CSS, zero JavaScript) served in a `sandbox="allow-same-origin"`
  iframe. It reflows on resize with the browser's own layout engine and carries the app's exact colors
  (no rasterisation), so panning, zooming, and device-sweeping a board is smooth and pixel-honest. The
  full live app sits underneath and swaps in instantly when you focus a frame (double-click), or in
  laser/comment mode. This replaces the earlier screenshot facade, which invented colors and jittered.
- **Publish parity.** The lean tier now works in published builds (`marver build` → `marver serve`),
  not just dev - captured client-side from the bundled same-origin frames, no build-time renderer.
- **Faster first paint.** Leans capture bounded-parallel and viewport-first, so the frames you're
  looking at appear first and a big board settles in seconds instead of tens of seconds.
- **Content-frame color families.** Tag a diagram node with a built-in family - `HQ:::blue`,
  `Carriers:::orange`, `Drivers:::purple` (also `green red gray`) - and it gets a filled, on-brand
  color with a legible border in both themes, no `classDef` boilerplate. The same six names work in
  `Md` prose as `:blue[the shipper's world]`, so a sentence and the diagram beside it read as one
  color language.
- **`Head :: gloss` diagram labels.** A node label written `Head :: gloss` renders the head bold on
  top with the gloss lighter and smaller below - a box scans as label-then-detail, no run-on.
- **Authoring doctrine that ships with the tool.** The scaffolded instructions
  (`instructions/shape.md`, `instructions/reference/color.md`) now teach an agent these conventions -
  the `::` label hierarchy, the `:::family` / `:blue[…]` palette, and "pick one family per concept and
  hold it" - so diagrams and highlighted prose come out consistent by default instead of hand-rolled
  hex and one-off `classDef`s.

### Changed

- **Sidebar header** shows the humanized repo name (`marver-pilot` → "Marver Pilot", ellipsed if
  long); the logo links to marver.design.
- **Sidebar board/scene labels** are humanized - kebab filenames render Title Case (`crm-specs` →
  "Crm Specs"), dropping the dashes, while an explicit `meta.title` is honored verbatim.
- **App cursor** is the marver arrowhead - tilted, rounded, small, soft-shadowed, and theme-adaptive
  (black-on-light / white-on-dark); reverts to a normal pointer in interact/prototype and keeps the
  pin/crosshair in comment/laser mode.
- **Copy-file-path shortcut** moved to `Shift+P` (was a mislabeled `C`).

### Fixed

- The canvas "jiggle" - text shifting ~1-2px when you click or zoom a frame - is gone; there is no
  longer a per-gesture document swap to shift it.
- Mermaid diagrams no longer pop in/out or flash the wrong theme during zoom (async render is awaited;
  a diagram's baked colors re-capture on theme change; the cover's color-scheme is pinned to the
  frame theme, not the viewer's OS).
- A frame you've scrolled, typed into, or themed re-captures faithfully; agent edits (HMR) drop the
  stale snapshot and rebuild; slow data that lands shortly after load triggers one bounded re-capture
  (data that changes much later shows live the moment you focus the frame, and the lean rebuilds when
  you leave it).

### Known limitations

- Memory targets typical authoring boards (~15-20 frames); dozens of heavy production apps need the
  bounded-residency milestone. A frame the serializer can't render faithfully (canvas/video/open- or
  script-created-closed shadow-DOM/nested-iframe/cross-origin-CSS/blocked-CSP/oversized) degrades to
  live automatically. (One narrow edge: a declarative closed shadow root can't be detected and may
  render stale - rare in practice.)

## 0.4.0 - 2026-08-14

The collaboration release (SPEC-M3): the canvas becomes a place where colleagues,
the designer, and the coding agent close the feedback loop together.

### Added

- **Element-anchored comments.** `C` enters comment mode: click any element inside a
  frame (laser outlines guide you) and the thread pins to it - fractional position
  inside the element's box, so pins ride through responsive reflow. Threads are
  Google-Docs-shaped: root + one level of replies, resolve/reopen. Anchors survive
  agent edits via a verified ladder (semantics → CSS path → fuzzy quote match);
  a dead anchor parks the thread visibly at the frame edge, never silently deleted.
  Inactive frames collapse their open threads into a top-right avatar stack.
  `Shift+C` hides all pins; `?c=<thread>` deep-links a specific thread through the
  password gate (copy-link on every card).
- **Real commenter identity, no email infrastructure.** Viewers on a published canvas
  claim an account through a single-use invite link (owner mints it; the link travels
  over Slack/DM) - display name, password, avatar. Accounts are scrypt-verified with
  per-user salts; sessions survive restarts. The first account owns the canvas;
  `MARVER_OWNER_EMAIL` prints the owner's one-time claim link in the deploy logs.
  Avatars fall back to initials on a deterministic color.
- **Gate v2: one credential per persona.** The gate on a collaboration canvas has
  three doors: guests pay the canvas password (read-only), members sign in with
  their OWN password (their session IS gate passage - they never touch the shared
  secret), and an invite link (`<url>/#/i/<token>`) opens straight into the claim -
  email shown as an INVITED chip, profile-picture picker (client-side 128px
  downscale), display name, password. Sign-in/claim endpoints sit in front of the
  gate (rate-limited, non-enumerating); rotating the canvas password only ever
  affects guests. Primary buttons stay disabled until their mandatory fields are
  filled, with a tooltip naming what's missing. The boards payload carries the
  owner's display name, so a read-only refusal says who to ask. Static canvases
  keep the single-field gate untouched.
- **One deploy, comments live everywhere.** `marver serve` grows a collaboration API
  (REST + SSE) when `MARVER_DATA_DIR` names a durable volume; the published canvas is
  the comments' home. `marver dev` two-way syncs every 30s (`marver comments connect
  <url>` once), so client feedback lands in `design/comments/<board>.jsonl` - a
  git-tracked, append-only event log the agent reads with zero tooling. Republishing
  never clobbers collected feedback (the store unions the bundle seed on boot).
- **The agent works the queue.** `marver comments list --open --json` / `reply` /
  `resolve --addressed-in <frame>` - resolving records which variant answered the
  feedback, making the fork-don't-overwrite doctrine auditable. `marver comments
  invite <email>` mints single-use invite links from the CLI (owner only), `revoke
  <email>` retires an account. `instructions/iterate.md` carries the
  comments-as-work-queue discipline; `instructions/publish.md` is the agent-facing
  deploy runbook (boards policy, gate, volume, accounts) and AGENTS.md routes to it.
- **Laser mode.** `L` (or the toolbar crosshair) outlines every element in every frame
  with depth-hued borders (60° per nesting level) plus a DevTools-style hover label.
  Zero layout shift - outlines only. Clicking an element copies its full address for
  the agent - frame source file + CSS path (+ JSX source location when stamped).
  Comment mode shows only the hover highlight (no full rainbow) and a chat-teardrop
  cursor, so picking an element to comment on stays calm.
- **Default-closed publishing.** `marver build` now requires a publish policy:
  `design/publish.json` names each published board with `read` or `comment` rights
  (enforced server-side, not just hidden in UI). `--boards a,b` stays as an explicit
  override; publishing everything takes a deliberate `--all-boards`.

### Changed

- **`c` is comment mode now** (the Figma/Miro convention). Copy-selected-file-paths
  moved from `c` to `y`.
- `marver build` without a publish policy fails with instructions instead of
  publishing everything - the privacy default flipped closed.

### Security

- Comment mutations are CSRF-protected (double-submit cookie + origin checks) and
  rate-limited; session and invite tokens are stored hashed; every pushed event is
  validated hard (author must match the session, thread ids cannot be hijacked,
  edits are owner-only, timestamps cannot come from the future) - and accepted
  events are never rewritten, so id-keyed sync converges byte-identically.
- v1 trust boundary, stated plainly: frame code in your design repo runs same-origin
  with the shell - review what you merge. Full frame sandboxing is the v1.1 follow-up
  (SPEC-M3 §0 records the probe results and the plan).

### Durability & concurrency

- Comment appends and auth writes are `fsync`'d before they are acknowledged - a
  comment or account confirmed to the client survives a crash or volume interruption,
  not just the page cache.
- `auth.json`'s read-modify-write is guarded by a cross-process lock (stale-stolen
  after 10s, never deadlocks) so a deploy overlap or an accidental second instance
  cannot resurrect a revoked account or drop an invite. The comment log needs no lock:
  append-only + id-keyed union is conflict-free by construction (and git merges it
  with `merge=union`). Two honest v1 limits, documented not hidden: thread ordering
  uses client timestamps (a badly-skewed clock can mis-order a resolve/reopen race -
  re-resolve to fix), and comment logs have no hard size ceiling (fine at the design-
  review scale marver targets; a per-board cap is a later concern).

## 0.3.1 - 2026-08-13

### Fixed

- Play-mode variant chrome: the current variant's name was invisible (theme ink on the always-dark glass pill - now the pill's own light ink), and switching variants jiggled the controls. Redesigned: the letter chips now use the sidebar's exact badge language (20px, 7px-radius, one shape in every state) so the two surfaces read as one concept, they LEAD the cluster as the stable anchor, and the name trails at natural width (capped with ellipsis + a tooltip carrying the full title) - a name change grows the pill rightward without moving anything underfoot.

## 0.3.0 - 2026-08-13

The co-thinking release: the canvas now holds the thinking, not just the screens.

### Added

- **Content frames (SPEC-026).** Specs, Mermaid diagrams, and mood boards as ordinary frames beside UI frames - import `Doc`, `Row`, `Col`, `Space`, `Md`, `Diagram`, `Img` from `@marver-design/marver/content`. Works in a repo with no app at all: idea first, design second.
  - `Doc` auto-sizes the frame to its content (measurement protocol; auto sizes are session-transient, manual resize and device views still win). Published canvases keep parity.
  - `Diagram` is first-class Mermaid, lazily loaded - a workspace with no diagrams ships zero mermaid bytes. Source theme overrides are stripped; parse errors show an in-frame card and heal live.
  - `Md` renders theme-aware markdown; `[label](goto:scene/frame)` links jump the canvas. Raw HTML is inert, images are local-only.
  - `Img` shows `design/assets/` imagery with captions; `h={n}` cover-crops a mixed-aspect row to one height so it reads aligned.
  - Zero-external-request boundary: URLs are rejected in diagram source, rendered SVG is sanitized, published builds copy only referenced local assets.
- **The marver diagram theme.** Full Apple system palette (12 series colors + systemGray ramp, exact HIG light/dark pairs), system font stack, accent-washed nodes by default - a plain flowchart is never gray-on-gray. Label typography rides inside the SVG (measured, not post-styled).
- **Frame intent.** Content frames declare `intent` (`diagram` | `spec` | `moodboard` | `notes`); the sidebar shows a glyph per row - every row leads with an icon, variant groups carry the flask.
- **Sidebar tells the canvas's story.** Rows and scene groups order by canvas position, not file order.
- **The onboarding fork (SPEC-025 amendment).** Both first-session paths - empty repo and existing app - now stop and ask what the highest priority is: think the idea through together on the canvas, or go straight to screens.
- **Shape & Iterate doctrine.** `instructions/shape.md` (feature-story boards: specs → lo-fi → hi-fi with graduated spacing) and `instructions/iterate.md` (fork-don't-overwrite, letter variants, the archive ritual).
- **Craft doctrine hardened.** Real assets are binding (Phosphor icons by default, actual brand logos, fetched imagery). Interactive means visibly interactive at every fidelity - cursor + hover on every clickable target, component-library gaps (shadcn on Tailwind v4 ships `cursor: default` buttons) fixed at the design-system base layer.

### Changed

- Markdown typography moved to the HIG scale: 16px body on 1.65, tightened heading tracking, contained Notion-style tables, re-asserted list markers (Tailwind preflight strips them in host apps).

## 0.2.4 - 2026-08-13

- Onboarding as a conversation (SPEC-025): setup flow asks what you're building, proposes a stack (a recommendation, not a requirement), hosted tour canvas as the waiting room, local canvas as the reveal. Two dogfood rounds folded in.

## 0.2.3 - 2026-08-12

- Hardening release: live-JOIN adjacency, same-directory group invariant, tsx-only inference, extractor boundaries, sceneRows dedupe, play-mode chrome fixes, extreme-zoom badge fade.

## 0.2.2 - 2026-08-12

- Update discovery: glass pill + stdout notice + daily registry check (opt out with `MARVER_NO_UPDATE_CHECK=1`). `design/` collision guard on init.

## 0.2.1 - 2026-08-12

- The dogfood friction release: all 23 logged friction issues triaged; bugs fixed.

## 0.2.0 - 2026-08-11

- First public release on npm as `@marver-design/marver`, Apache-2.0. The agent-native design canvas: `design/` folder, live frames from your app's real components, boards, device sweeps, play mode, published canvases with a password gate.
