Releases: Cavalry-Collective/visual-stack
Release list
v6.4.0
Changed
- One place decides what the product looks like. The palette now comes from
design/tokens.css, the design guide's token source, instead of being decided
in the shared shell. Every page — the review workspace, the story map, the
spec tree, the build board, the chooser — picks up the guide's Cavalry brand:
purple-cast neutrals in place of the cool greys, and the brand red at the step
that holds its contrast on white. Nothing moved and nothing was renamed; only
the colours changed. - Dark is now part of that source rather than something the shell decided on its
own, so both themes come from the same place.
v5.0.0 — mark a page by moving things and striking things out
Breaking
- Stop is withdrawn. Asking the agent to stop a round mid-flight could not
do the one thing it promised — interrupt the turn — so it is out rather than
half-working. Thecancelledcommand,/api/cancel, thecancelsentinel
and theCANCELLEDstream event are gone, andcheckalways exits0. A
round already on disk with statuscancelledstays terminal, so nothing in
your project needs migrating. What it would have to do to come back is written
down indocs/review-wishlist.md. - Host profiles move to
plugins/vstack/host-profiles/.hosts/now holds
only the adapter markdown that maps review operations to a product's tools.
This is inside the plugin, so an installed copy updates itself.
Added and fixed
- Linked now means a session is listening. The workspace used to show Linked
on evidence a session could produce without receiving anything. A stream
watcher now opens with aHANDSHAKEline naming a command, and its heartbeat
only starts onceackanswers it; unanswered, the watcher exits after two
minutes (--handshake-timeout <seconds>). Presence also requires rounds to
move: one queued and unclaimed for 90 seconds drops the link, because a
watcher whose events nobody reads should look the same to you as no watcher at
all. A watcher covering no review reportsUNLINKEDrather thanLINKED. - The cog says which version you are on. It shows the version the workspace
loaded with and the one the server is running now, and offers a reload when
they differ — so a tab left open across an update says so. - An answer written on a comment carried in from an earlier version is kept.
Replies and note edits copy the comment into the current version first, so the
answer lands in the file the workspace reads back. - Two new ways to mark up a page: Move and Delete. A toolbar beside the page
holds Comment, Move and Delete — what Annotate draws with, on keysc,m
andd. Neither new tool needs a note: the mark is the instruction, and
anything you type adds to it. Both outline whatever the pointer is over, so
the element the gesture will take is settled before you press.- Move draws an arrow from a thing to where it should go. It records the
element you dropped it on and which side of it — inside, before, or after —
so your agent is told "after the Cancel button" rather than "180px right",
which stops meaning anything the moment the page reflows. - Delete strikes out what should go. Drag across text and exactly those
words are marked for removal; the strike finds them again by their text when
the page is rebuilt, so it stays on them. Click an element instead and the
whole thing is marked.
- Move draws an arrow from a thing to where it should go. It records the
- A watcher finds a review whose page lives outside the directory it was
started from. A review's files sit beside the page under review, and
watch --allfound them by walking the directory it ran in. A page written to
a temp directory took its files with it, so the watcher walked straight past a
running review and the workspace said Unlinked while a session was in fact
listening. Serving now leaves a pointer where it was run from, and the watcher
follows it. - A watcher that covers no review says so. It reports
UNLINKEDinstead of
LINKED, because nothing is listening to any workspace at that point whatever
the handshake proved. A handshake also carries the token it printed, so one
watcher's answer no longer brings a different watcher live.
v4.8.1 — the send button is readable when the workspace is dark
- The comment composer's send button is readable in dark mode. Its label was
fixed to white while its background follows--ink, which is the text colour
and therefore near-white under a dark theme. The button rendered as a blank
white box, at a contrast of 1.12:1. The label now follows--surface, the
pairing the rest of the interface already uses, giving 15.70:1 in dark and
leaving light mode exactly as it was.
| Theme | Before (#fff) | After (var(--surface)) |
|---|---|---|
| Light | 17.90:1 | 17.90:1 — unchanged |
| Dark | 1.12:1 | 15.70:1 |
Update
/plugin marketplace update cavalry-collective
/plugin update vstack@cavalry-collective
/reload-plugins
Full changelog: https://github.com/Cavalry-Collective/visual-stack/blob/main/CHANGELOG.md
v4.8.0 — the plugin has a version, and a comment stays on its own element
- The plugin declares a version. Until now it shipped without one, so every
commit tomaincounted as a release. Your host now compares version numbers
and updates when this number changes. A copy installed before this release has
no version on record and keeps comparing commits until it updates once. - A comment lands on the element it was left on, not a lookalike. The
selector recorded for a comment was cut off after eight steps, and a short
path can first-match a different element elsewhere on the page, which is the
onequerySelectorreturns. The recorded selector is now the shortest one
that matches a single element, and a path still ambiguous at full length is
rooted atbodyso the chain is exact. - Reanchoring prefers the element carrying the comment's words. When a
selector still parses but its match shares nothing with what was captured, an
element scoring on text or identity is now taken ahead of it. - Both host manifests carry the full set of distribution metadata: version,
display name, homepage, repository, license, and keywords covering what
someone would search for. Descriptions across all three manifests are drawn
from the README. - CI runs the tests on Node 18 and 22, checks the stamped shell for drift, and
validates both manifests with the same tool the community-marketplace review
pipeline runs. A release workflow rejects a tag that disagrees with the
manifest version. - Issue and pull request templates, a changelog, and a release procedure in
CONTRIBUTING.md.
Install
/plugin marketplace add Cavalry-Collective/visual-stack
/plugin install vstack@cavalry-collective
Already installed:
/plugin marketplace update cavalry-collective
/plugin update vstack@cavalry-collective
/reload-plugins
Full changelog: https://github.com/Cavalry-Collective/visual-stack/blob/main/CHANGELOG.md
v4.7.0 — a carried question is on the list
v4.7.0 — a carried question is on the list
A question Claude asks is carried onto the next version, because it is the one
thing in a review waiting on the reviewer. The panel was not drawing the
carried ones. They were counted in the bar below the list, in the server's
unresolved set and in the check that guards sign-off, but there was no card for
them — so no × to dismiss one and no box to answer it in.
Every group in the list now decides "still live" the same way, and a carried
question sits with the other questions at the top, its reply box already open.
A carried card says which version raised it, as from r3 in a live app review
and from v3 in a wireframe review. A question asked ten rounds ago no longer
looks like one asked a minute ago.
The walk over earlier versions sorts explicitly. Which copy of a comment you
see depends on later versions being read last, and that held only because
integer-like object keys happen to iterate in order.
v4.6.0 — the tool is review
The wireframe tool is now /vstack:review, and the review loop stops losing comments across a version bump.
The tool is review
/vstack:wireframe still works, as a thin alias that reads review/SKILL.md and nothing else. A review opened on a clean install writes to .vstack/local/review/<name>/.
Rounds already under .vstack/local/wireframe/ keep working. workdir.mjs holds a LEGACY map of what a tool used to be called, reads a subject from whichever directory already has it, and creates new ones under the current name — so watch --all still finds a review opened before the rename. Nothing is migrated behind your back.
The project-planning tools — spec, start, phase-build, phase-preview and the go alias — move to experimental/, where no host discovers them. review and user-story-map are what ships.
Three ways a comment could go missing
- A save deleted what it did not mention. A save reports what one tab holds, which is never the whole review: comments carried from an earlier version are absent from the payload, and a second tab knows nothing of what the first just wrote. The server merged those saves field by field but replaced them set-wise. Merging is now a union — removing a comment is
dismissed, a field, not an absence. - A reply went to whichever version still had the comment. It scanned every review file and took the highest, so once the delete above had pruned the comment from the current version, the reply landed in a stale file nothing renders — and the command reported success. A reply now targets the version the workspace has open, copying the comment forward when it exists only in an earlier file.
- A question did not survive the next version. Open and addressed comments were carried onto a new version;
questionwas not. A question is the one status waiting on you, so Claude's question left the screen at the next publication with nobody able to answer it.
Regression tests cover the first two, and fail without the fixes.
In the workspace
- Comments anchor to what you clicked on a page that scrolls its own window. The overlay gave a position in the frame's window and everything downstream read it as a position in the document; the two agree only while the page never scrolls.
- Addressed comments read green across the mark, the card and the composer, and selecting one brings its mark back to the page.
- The workspace opens itself, and narrow widths keep the top bar's meaning without its words instead of taking over the window.
- A review says where its files are rather than assuming.
Underneath
One live-link client and one heartbeat protocol shared by the review server and the JSON bridge. Every server injects the host profile, so no page bakes in a product name — a Codex-served board says Codex. Four bugs found in a deep-review pass, the Grok adapter taught the current protocol, and 1.6M of dead brand and mockup assets removed.
v4.5.0 — .vstack/local/<tool>/
Corrects the layout v4.4.0 shipped a few hours earlier. Machine state and pipeline state now split first; the tool name comes second.
.vstack/
pipeline.json ← tracked
specs/feature.json ← tracked
build/phase-1.json ← tracked
local/ ← gitignored, one line
wireframe/login/
spec/feature.seq
user-story-map/map.seq
phase-build/phase-1.seq
What was wrong with 4.4.0
bridgewasn't a tool. It namedlib/json-bridge.mjs, an engine that spec, user-story-map and phase-build share — not anything anyone invokes..vstack/spec/would have sat one letter from.vstack/specs/— machine scratch beside a tracked pipeline file, distinguished by a plural.- Every new engine meant another
.gitignoreline.
Splitting on machine-vs-repo first fixes all three: **/.vstack/local/ is the only ignore line needed, ever, and the tool name lives one level down where it can't shadow a tracked directory.
The bridge knows who it serves
json-bridge.mjs takes --tool, so the three skills that share it get their own directories. All three SKILL.md files pass it on every serve, watch and patch.
A skill that passed --tool to serve but forgot it on watch would resolve to a different directory and silently watch nothing — the worst failure this design allows. findWorkDir makes a reader fall back across sibling tool directories, so the link works even when the calls disagree.
Tests
New tests/workdir.mjs covers the resolution rules: state sits beside the artifact, an enclosing .vstack wins over nesting a second one, the tool name is always last, spec is never spelt specs, and the reader fallback works.
Breaking
If you took 4.4.0, the paths moved again. Still no migration — reviews in flight and in-browser comment drafts are orphaned. Finish or discard any open review before updating.
Update
Claude Code:
/plugin marketplace update cavalry-collective
/plugin update vstack@cavalry-collective
/reload-plugins
Codex:
codex plugin marketplace upgrade cavalry-collective
codex plugin add vstack@cavalry-collective
v4.4.0 — one .vstack directory
The tools stop scattering dot-directories. Everything they write for one machine now lives under .vstack/, one subdirectory per tool.
| Was | Is |
|---|---|
.ui-review/<name>/ |
.vstack/wireframe/<name>/ |
.vstack-bridge/ |
.vstack/bridge/ |
How the path resolves
State still sits beside the artifact it belongs to, so a review of design/login.html lands in design/.vstack/wireframe/login/ and moving the page moves its review with it. lib/workdir.mjs is the one place that decides: the enclosing .vstack when the artifact already lives in one — the spec tree writes .vstack/specs/<feature>.json, and nesting .vstack/specs/.vstack/bridge/ under it would repeat the name — otherwise the .vstack directly beside it.
.gitignore ignores the two tool directories at any depth rather than .vstack/ as a whole, because pipeline.json, specs/ and build/ are the pipeline and belong in the repo:
**/.vstack/wireframe/
**/.vstack/bridge/Breaking
Reviews in flight under .ui-review/, and comment drafts under the ui-review:* localStorage keys, are orphaned. There is no migration. The files stay on disk; the tools no longer look there. Finish or discard any open review before updating.
The old paths deliberately kept their names for two releases to avoid exactly this. That stopped paying once one product meant three dot-directories in a project.
Update
Claude Code:
/plugin marketplace update cavalry-collective
/plugin update vstack@cavalry-collective
/reload-plugins
Codex:
codex plugin marketplace upgrade cavalry-collective
codex plugin add vstack@cavalry-collective
v4.3.0 — Codex joins the hosts
Visual Stack is no longer Claude-Code-only. Codex runs the wireframe workflow, and the review workspace stops losing work.
Highlights
- Codex host — install Visual Stack from the Codex marketplace and invoke
$wireframeto build or review a UI in the annotation workspace. Wireframe is the only stage with a Codex adapter so far; the rest of the pipeline stays Claude Code (and Grok Build). - Host contract, filled in —
hosts/codex.jsoncarries Codex's labels, capabilities and update commands;skills/wireframe/hosts/codex.mdmaps the Host ops onto Codex tools. Skills still depend only on the contract, never on a particular agent product. - Clear all asks first — clearing a review used to arm a button for three seconds. It now opens a confirm dialog that says how many comments go and that the wireframe and version history stay.
- The panel keeps its own edge — the comments panel and its handle sit on real grid lines, so the handle tracks the panel under browser zoom. Below 720px comments become their own full-width view instead of a drawer covering the page under review.
- No more rolled-back edits — merging server state no longer undoes a local dismissal, reply or reopen that is still inside the autosave window.
Also in this release
tests/host-profiles.mjsvalidates every host profile against the schema- The review-lifecycle test serves under
--host codexand asserts the workspace gets the right host identity - README and CONTRIBUTING cover the Codex install and how to test a Codex change
Install / update
Claude Code:
/plugin marketplace add Cavalry-Collective/visual-stack
/plugin install vstack@cavalry-collective
Already installed:
/plugin marketplace update cavalry-collective
/plugin update vstack@cavalry-collective
/reload-plugins
Codex:
codex plugin marketplace add Cavalry-Collective/visual-stack
codex plugin add vstack@cavalry-collective
v4.2.0 — phase-preview, live review, shared shell
The workspaces share one shell, wireframe reviews real apps, and every push to main is a release.
Highlights
- Shared shell — one top bar, palette, theme, and scrubber for every tool page. Theme and language sit behind a settings cog so the bar only carries the tool and its work.
/vstack:phase-preview(wasphase-wireframe) — drag through release phases on the same scrubber; each stop is the approved design with later work taken out.- Live wireframe review — point the workspace at a localhost app or a public site; it proxies the real screens so comments land on them, not a mockup.
- Update check — each local server asks once whether
mainhas moved on (install SHA vs head), and shows one dismissable line when it has. Noversioninplugin.json; every push tomainis the release. Opt out withVSTACK_NO_UPDATE_CHECK=1.
Also in this release
- Spec, start, story map, and phase-build follow the quieter bar and shared chrome
- Handoff footers on wireframe, story map, and phase-preview so the pipeline reads end to end
- README rebuilt around interactive specs and how updates work
Install / update
/plugin marketplace add Cavalry-Collective/visual-stack
/plugin install vstack@cavalry-collective
Already installed:
/plugin marketplace update cavalry-collective
/plugin update vstack@cavalry-collective
/reload-plugins
Or turn on auto-update under /plugin → Marketplaces → cavalry-collective.