本文へ移動
cccskills
無料GitHub で公開

review

Visual Stack's primary tool. Build a UI wireframe and open it in an interactive review workspace where the user comments directly on the page, turning those comments into the next iteration — or point the same workspace at an app that is already running and review the real thing. Use when the user wants a wireframe, UI mockup, screen design or prototype built; wants to review, annotate, mark up or comment on a page, a design, an existing UI, a running app or a website; wants to iterate on a UI; asks to use Visual Stack; or invokes $vstack:review, /vstack:review, or the older /vstack:wireframe.

インストール方法を見る

含まれるファイル(17)

  • SKILL.md36.3 KB
  • assets/bundle-artifact.mjs5.2 KB
  • assets/harvest-reference.js5.7 KB
  • assets/review-server.mjs107.3 KB
  • assets/screen-template.html2.1 KB
  • assets/workspace.html272.1 KB
  • hosts/claude.md3.9 KB
  • hosts/codex.md5.5 KB
  • hosts/grok.md5.0 KB
  • references/design-sources.md4.3 KB
  • references/workflow.md17.1 KB
  • tests/design-tokens.mjs5.9 KB
  • tests/host-profiles.mjs2.7 KB
  • tests/review-lifecycle.mjs22.2 KB
  • tests/round-gate.mjs9.3 KB
  • tests/update-check.mjs3.8 KB
  • tests/workdir.mjs3.2 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

0 · Host (do this first)

This skill is tool-agnostic. The loop is defined in plugins/vstack/contracts/review-loop.md and the ops you need in plugins/vstack/contracts/host.md. Never invent host-specific tool names in this file — they live only in the Host adapter.

You are running under…Load adapterSet
Codexskills/review/hosts/codex.mdVSTACK_HOST=codex (or --host codex on serve)
Grok Build / Grok CLIskills/review/hosts/grok.mdVSTACK_HOST=grok (or --host grok on serve)
Claude Codeskills/review/hosts/claude.mdVSTACK_HOST=claude (default if unset)

Adapters live in the hosts/ directory beside this SKILL.md. Do not read plugins/vstack/host-profiles/<id>.json instead: that JSON is UI data with no tool mapping.

Read the adapter before §3. Every background, watch_stream / watch_next, stop, share, and browser_capture step is fulfilled exactly as that file says.

A two-way review loop. The user comments on the screen; you apply the comments, ask about anything ambiguous, and publish the next version. Two things can go under it:

what it iswhat you change
A page (§1–§3)a wireframe you just generated, an exported screen, a prototype — any self-contained HTML filethe file
A UI that exists (§7)an app on localhost, or a website on the internet: the real screens, real data, real statesthe source code — or, for a site you don't own, a note about it
requirements ──► page.html ──► review workspace ──► brief.md ─────┐
      ▲          or a live app  (user comments)                    │
      └──────── you apply it, reply, publish v(N+1) ◄──────────────┘

One review is one subject. A page review opens that file and nothing else — several screens means several files and several workspaces, not an invented project structure. A live review opens the whole app, because clicking through it is the point.

Which one? If the thing the user wants to talk about already runs, review it running (§7) — a wireframe of a screen that exists is a copy that drifts. Build a page when the screen does not exist yet, or when they want to change it without changing code.

1 · If you are generating the page

Skip to §3 if the file already exists.

Establish before building — ask only what you genuinely can't infer, in one message:

  • What screen, and what the user is trying to do on it.
  • Which screen size leads — the workspace offers ultrawide (2560), desktop (1440), tablet (834) and phone (390).
  • Visual reference — a site to match, screenshots to match, or the project's design system (§2). If they name a site or hand you images, capture it before building (§2a).
  • States — which loading / empty / error states matter enough to be shown.

Keep the first pass deliberately lean. The review loop is how it gets rich; a bloated v1 wastes the user's first review on deletions.

2 · Resolve the design source

In priority order — see references/design-sources.md for the detail:

  1. A reference site the user names — capture it (§2a) rather than describing it from memory.
  2. Reference screenshots the user provides — Read every one and derive the same, saying what you inferred.
  3. The project's design system — a design/ folder with tokens.css (+ often design-guide.html, CLAUDE.md). Use its tokens verbatim. If it ships its own principles doc, read it and follow it — it outranks the defaults below.
  4. Nothing found → ask, don't invent silently.

2a · Building from an existing site

A URL or a screenshot is a design source, not a description of one. When the user says "like Linear", "match our admin", or drops a screenshot in, don't work from an impression of it — capture it, write down what you measured, and build against those numbers.

With a URL, use Host op browser_capture when the adapter says it is available; otherwise ask the user for screenshots and derive by eye (§2 screenshots path). The full procedure — screenshots per size, assets/harvest-reference.js, writing <page-dir>/<name>-reference.md so every later pass reads it instead of re-capturing, the never-sign-in rule — is references/design-sources.md §1–2. Copying a layout is the point; logos, wordmarks, photography and copy stay placeholders.

Default principles, unless the design source overrides them:

  • Start simple. The minimum UI that serves the task.
  • Follow the patterns users already know from established tools in the domain. Novelty needs a defensible reason.
  • Growing collections are datagrids — search, sort, filters in the headers, pagination — not card walls.
  • Order by attention, place by belonging. What the user needs first goes first; metrics last.
  • Realistic data. Causally consistent, credible scale, real edge cases. Never a fake zero — undefined is an em dash.
  • No commentary, no dead controls.

Requirements the workspace places on the file:

  • Self-contained — tokens inline in :root, no external fonts, stylesheets or scripts. The same file has to work served over http and inlined into a share bundle.
  • A real <title> — the review is named after it.
  • min-height: 100vh, never height: 100vh or overflow: hidden on body — the page lays out at full height inside the workspace's window.

3 · Publish and serve

SKILL=<this skill dir>          # the directory containing this SKILL.md
FILE=wireframes/candidate-pipeline.html
# Prefer export VSTACK_HOST=<id> once; --host on serve is required for correct UI labels.

node "$SKILL/assets/review-server.mjs" publish --file "$FILE" --label "Initial version"

Start the server with Host op background (it must outlive the turn) — see your adapter for the exact tool:

node "$SKILL/assets/review-server.mjs" serve --file "$FILE" --port 7788 --host "$VSTACK_HOST"

The server opens the workspace in the browser itself, as soon as it is up. Say it is open and name the URL — http://localhost:7788/ — so a machine that could not open anything still has it, then arm the waiter (§5). Pass --no-open when the user asked you not to take over their screen.

Reviewing a running app instead? Same server, --app in place of --file — see §7.

4 · What the user gets

The page opens in its own browser window on the canvas — own viewport, own scrollbar — so nothing about the workspace bleeds into the design being judged.

View / Annotatetwo modes, esc toggles. View hides every annotation so the page is judged as it really is; Annotate brings them back
Clicka comment pin at that spot
Dragan area comment over that region — it carries the element that contains the box and everything named inside it
Either waythe note opens on the canvas where the mark is. A comment with nothing typed in it is discarded on dismiss
Toolbar (left of the canvas)what Annotate draws with: Comment · Move · Delete, keys c · m · d. Picking one in View mode returns to Annotate with it
Move and Deleteboth are optional-note: the mark is the instruction, and anything typed adds to it. Both outline whatever the pointer is over, so it is clear which element the gesture will take
Movedrag a thing to where it should go. Arrives as kind: move — the element to move, the element it was dropped on, and which side of it
Deletedrag across text to strike exactly those words, or click an element to strike everything written inside it. Arrives as kind: strike
Targetthe note says which element the comment attached to
Attached to an elementa comment belongs to the thing it was made on, not to a coordinate. The mark rides it when the layout moves, and goes off the page with it — a comment made inside a modal, tab or step is not drawn while that thing is closed. It stays in the list tagged not on screen, and it still reaches you
Captionsstay hidden — a mark shows its note when it's open, or on hover in Annotate
Screen sizeultrawide · desktop · tablet · phone. A comment belongs to the size it was made at and only shows there
Threadyour replies appear on the comment itself and in the comment list, where they can be answered without going back to the mark. A question opens its thread on sight. A question that came with options shows them as buttons, one marked Recommended; pressing one answers with those words, and the box below still takes anything else
Save (⏎)on the comment — Enter commits it, Shift+Enter is a new line
Timeline (bottom)drag the handle to scrub through published versions; history is read-only
EN / 中文workspace chrome only — comments stay in whatever words they were written in
Deleteon the comment, once it has words in it. It takes the comment off the user's list whatever state it is in, including one you are working on right now — you are not told, and you finish and close what you were given as normal
Clear allin the comment list footer, behind a confirm. It takes the addressed comments off the list — the same act as the per-card delete. Comments still open stay unless the reviewer ticks the box on the confirm, which is off every time it is asked
Link statusa dot beside Send — linked to your session, or link lost. Nothing is said until the connection has actually answered
Send to {agent} (⌘⏎)sends straight through — no preview step — and wakes you up. Label uses the Host profile name. Greys out until something actually changes
In flightone comment keeps an indeterminate progress bar until you publish or reply. Later comments remain queued, and a question waits on the reviewer without blocking the next ready comment
Stalledafter a minute with nothing listening, the strip stops claiming progress and says you have stalled. Send again puts the active comment back in the queue for the next session. Refused while your watcher is alive, because then you still have it
Addressedcomments you closed stay in the list in their own section, each offering Revert or Refine
Publish a link to this wireframe (the ▾ beside Send)only when Host capabilities.share is artifact. Asks you to publish the wireframe (Host op share) and hand the URL back. Hidden on hosts without public share, and in a live review
Approve & finish (the ▾ beside Send)sign-off. Ends the review, closes the server, and tells you the design is settled — behind a confirm that warns how many comments are being left unapplied

There is no per-comment resolve button: you close comments out by addressing them. Approve is the whole-page verdict, not an item-by-item one — one click that means the design is done, which is the only way the review ends deliberately rather than by the tab closing. Comments arrive naming the element they were made on and the region it sits in; the user never sees markup, and the selector that comes with them is how the mark stays attached, not a promise about your HTML — keep ids and distinctive classes stable across versions and open comments keep their grip.

Addressed is your word for it, not the last word. A comment you closed can come back:

  • Refine reopens it as it stands — read the note and the thread again, it did not go far enough.
  • Revert reopens it asking you to undo what you did there, and posts that as a reply in its thread.

Either way the comment returns in the next brief with reopened: true (and wantsRevert: true for a revert), marked · REVERT in the markdown. Nothing else can un-address a comment — the server only accepts a status going backwards when the reviewer deliberately sent it back.

5 · Catch the review, and hold up your end of the conversation

After starting the server, start the watch operation your Host adapter names. A profile with capabilities.watch: stream uses watch_stream; pull uses watch_next. Either is a different op from the background you used in §3.

node "$SKILL/assets/review-server.mjs" watch --all --stream              # push Host
node "$SKILL/assets/review-server.mjs" watch --all --next --timeout 25   # pull Host

Use the exact command your adapter gives, not the bare forms above. It adds --session <your session id> when your Host has one, and that is what binds each delivery to you — without it, the round you take cannot be told apart from another session's.

--all takes in every review open in the project, including ones opened later, and any you started from this directory whose page lives elsewhere. It never takes over a push watcher another session already has. Run it from the same directory you started the server from; that ties the two together.

Push: it opens with a HANDSHAKE line naming a command. Run that command straight away. The watcher goes live once you answer. Answer within two minutes; after that it prints UNWIRED and exits, and you start it again via watch_stream.

Pull: one foreground call returns within the adapter's timeout. On IDLE, call watch_next again. On REVIEW, run the exact CLAIM command it prints immediately; only that command hands the comment to you and writes brief.md. An unread REVIEW offer leaves the comment queued, so another call or session can still receive it.

A bounded call delivers nothing once it has returned, and no process is left behind to notice that you stopped calling. Comments the reviewer sends then sit undelivered. Every call that ends prints the command that resumes it on a WAIT line, including the one you claim from — answer the round, then start the next wait.

The page says Linked while a push watcher is answered or a pull call's short consumer lease is fresh, and Unlinked in amber the rest of the time.

Each event is one line (full table: contracts/review-loop.md):

What it meansWhat you do
HANDSHAKEthe watcher asking whether you can hear itrun the command it prints, now — it is what brings the watcher live
LINKEDthe handshake is answered and a review is under the watcher; the workspace says Linkedcarry on — the loop is live
UNLINKEDthe handshake is answered, but the watcher found no review to cover, so no workspace says Linkedstart it again with --file <page.html> if a review is already running for a page outside this directory. A serve started here after it needs nothing
UNWIREDthe handshake went unanswered and the watcher exitedstart it again with the tool your adapter names for watch_stream
IDLEa bounded pull ended without an eventcall watch_next again while the review is open
WAITfollows IDLE and CLAIMED, carrying the command that resumes the bounded waitrun it — after you have answered the round, in the CLAIMED case
REVIEWpush: one comment was delivered; pull: a token was offeredpull Hosts run the printed CLAIM command first, then read the brief and continue below
DELEGATEthe reviewer handed one or more comments out to be worked on now, beside the one you are ongroup the related ones, start one Host subagent per group on their brief-<id>.md files, and carry on with what you were doing. See A comment handed out below
SHAREthey want a link to send someoneHost op share if capable, then §6; if the Host cannot share publicly, say so and offer a file/bundle instead
APPROVEDthe design is signed off; the server has closed itselfsay it's approved, note any openComments deliberately left, and carry on with whatever comes next
CLOSEDthat review's tab went awaythe watcher drops it and keeps watching the rest; it only stops when none are left

Use the protocol commands rather than deleting state files. share --url clears share, and closing a comment is publish --close.

What a delivery is

The watch operation waits until a comment is ready and none is active. A push watcher hands it over immediately; a pull watcher offers it and claim hands it over. Delivery contains one comment: the oldest first send or thread answer in the FIFO. A new comment or thread answer never interrupts the active one.

While you work, nothing will interrupt you. New comments accumulate on the server and arrive with the next delivery; a review in flight cannot be called off.

A comment handed out

The reviewer can hand a queued comment out rather than leave it waiting for you. They do it one card at a time, or turn on Parallel mode (Experimental) in the workspace settings, which hands out every queued comment at once and every comment they send after that. Either way it arrives as a DELEGATE event, the one delivery that does not wait for the active slot. One event carries every handed-out comment that was ready at that moment: it names each id, then each brief-<id>.md.

Do this with it:

  1. Keep going on the comment you are on, if there is one. A DELEGATE is not a change of subject.

  2. Read every brief the event names, and group the related comments. Comments are related when any of these holds:

    • they are anchored to the same element, or one is inside the other;
    • they are on the same component, or the same section of one route;
    • they ask for the same kind of change in one place, such as spacing across one list.

    A comment related to nothing is a group of one. When unsure, keep comments apart.

  3. Start one subagent per group — the op your Host adapter names — and give it the brief of each comment in its group.

  4. Scope each subagent to its group. Tell it to change only what its comments name and to leave the rest of the page alone. Nothing in the engine stops two workers editing the same file, so keeping them apart is yours.

  5. Hold a comment that touches what a running subagent is changing. Start its subagent when that one reports back. This applies to a later DELEGATE and to the comment in the active slot.

  6. Keep publish and reply to yourself. A subagent reports back to you. You close its comments with one publish --close <id>,<id> per group, so the review still speaks with one voice.

  7. Each comment is owed like any other delivery. unanswered counts it, and the Stop hook holds your turn open until you have closed it or replied to it.

With Parallel mode on, nothing takes the active slot. Your round is then: take the DELEGATE batch, group it, start the subagents, wait for them to report, and close each group.

Your Host offers this only when its profile says capabilities.subagents: true. Where it does not, the workspace shows neither the card control nor the setting, and no DELEGATE event is ever sent.

On a delivery:

  1. Read the brief the REVIEW line names (<store>/brief.md). It carries the active comment with its element, place, screen size and thread.

  2. Apply that comment. Locate it from its anchor — the element and the region it sits in — at the screen size it was made at, using the coordinates only to break a tie.

  3. Ask instead of guessing. If a comment is ambiguous, reply to it — the question appears on the mark and in the comment list, where the user answers it:

    node "$SKILL/assets/review-server.mjs" reply --file "$FILE" \
      --comment c7f2a1 --text "Every overdue row, or only the ones assigned to you?"
    

    The comment stays open and releases the queue. Its answer comes back in FIFO order after whatever was already ready. On disk the reply uses by: "agent" (legacy files may say "claude"; treat them the same).

    Write a paragraph break as \n, or as a real line break inside the quotes. Both reach the reviewer as a break, in --text, --option and --summary. Write \\n for the two characters.

    When the answers are a short list, offer them. --option, repeated, puts them on the comment as buttons, and --recommend <n> marks the one you would take. Pressing one answers with those words; the box to type something else stays, so an answer you did not think of is still one sentence away.

    node "$SKILL/assets/review-server.mjs" reply --file "$FILE" --comment c7f2a1 \
      --text "Every overdue row, or only the ones assigned to you?" \
      --option "Every overdue row" --option "Only mine" --recommend 2
    

    Two to four options, each a complete answer rather than a keyword. Ask an open question with --text alone when the answer is a sentence you cannot predict.

  4. If a comment is genuinely wrong for the design, reply saying why rather than silently skipping it.

  5. Close what you did, and snapshot the version:

    node "$SKILL/assets/review-server.mjs" publish --file "$FILE" \
      --close c1f3k2 --label "Filters collapsed" \
      --summary "Filters are collapsed behind a single control."
    

    Closing or replying releases the active slot. The watcher then hands over the next ready comment.

    --label names the version in one line. --summary is the account you would give in chat — what you changed, what you decided, what you left. The workspace shows it on the banner when the round lands, so a reviewer who is not reading your terminal still gets it. Send the same words to both places rather than writing a thinner version for the page. One summary is kept, and it is the latest one: a publish without --summary clears it.

  6. Check you left nothing hanging, before you finish your turn:

    node "$SKILL/assets/review-server.mjs" unanswered --all
    

    It exits 1 and names the active comment when you were handed it and then said nothing about it — neither closed nor replied. Until it is answered, the FIFO cannot move. Add --session <your session id> if your adapter names one, so the answer covers your deliveries and not another session's. On Claude Code a Stop hook runs this for you, with your session id, and holds your turn open until it is clean.

  7. Keep the adapter's watch operation active and say what changed in a few lines. Then wait — don't ask "shall I continue?", the loop is the point. A pull Host immediately starts its next bounded wait; a push Host leaves watch_stream running.

Closing the browser tab closes the review. The workspace holds an SSE connection; when the last one goes and none returns within the grace period (--idle-timeout, default 90s — long enough that a reload reconnects), the server removes url and exits. That exit re-invokes you and ends the waiter. --idle-timeout 0 keeps it up until you stop the background process (adapter). Either way, say when the review is closed — the user should never have to guess whether a socket is still open.

The workspace never swaps the page out from under the reviewer: while you work, each comment you were handed carries its own progress bar, and on publish the page offers a green line saying the round is done, with Refresh beside it and your --summary under it, behind a chevron that opens and closes and stays however the reviewer last left it.

6 · Publish the wireframe as a shareable link

Skip this section when Host capabilities.share is not artifact, or when the review is live — the UI hides the control in both cases, and there is no public URL backend. Offer a file path or bundle-artifact.mjs instead (adapter may say more).

What gets shared is the wireframe — the design itself, opening full-bleed the way the user will meet it. Not the review workspace: someone you send a link to is looking at the screen, not at your comment threads.

Do this when the reviewer asks in chat, or when the waiter returns SHARE — they pressed Publish a link to this wireframe under the ▾ and the menu is showing a spinner until the URL arrives.

Publish $FILE itself with Host op share (adapter names the tool), then hand the URL back so it appears in the workspace.

In a live review there is no $FILE — publish the capture the workspace just took, <store>/versions/v<n>.html for the current round, and say plainly that the link is a still of one screen, not the app. Take <store> from status (it reports store), never by building the path yourself: a review opened before this tool was renamed still lives under the directory it was created in.

node "$SKILL/assets/review-server.mjs" share --file "$FILE" --url "<public-url>"
  • Publish straight after a publish, so the file on disk is the version you're claiming to have shared. $FILE is the live working copy — mid-review it can be ahead of the last published version.
  • The page is already self-contained (§2).
  • The link is tagged with the version it came from. After a later round the menu offers Republish rather than a stale link — redeploy from the same file path so the URL stays put and anyone holding it sees the new version.
  • Delete the share sentinel once you've handed the URL back; share --url does it for you. Sharing does not end the review, and the watcher is still running.

If they want to comment remotely, that's a different package and an explicit ask. bundle-artifact.mjs flattens the whole workspace — page, last 3 versions, and the commenting UI — into one file; comments persist in localStorage and Send becomes Copy for {agent}, since there's no session at the other end:

node "$SKILL/assets/bundle-artifact.mjs" --file "$FILE" --out review.html

7 · Reviewing a UI that already exists

Point the same workspace at a running app and everything above still holds — the modes, the marks, the threads, the timeline, Approve. Three things differ, and they all follow from the same fact: what is under review is code, not a file you own.

node "$SKILL/assets/review-server.mjs" serve \
  --app http://localhost:5173 --name lora-ui --port 7788    # a dev server
node "$SKILL/assets/review-server.mjs" serve \
  --app https://example.com --name marketing --port 7788    # a site on the internet

The server reverse-proxies the app, so the workspace and the app share an origin — which is the only reason a comment can attach to an element rather than to a coordinate. The workspace moves to http://localhost:7788/__review/; every other path belongs to the app. Sockets are proxied too, so hot reload keeps working. Start it with Host op background, tell the user the /__review/ URL, and arm the adapter's watch operation (§5) against .vstack/local/review/<name>/ in the directory you ran it from — run every later command from that same directory, or pass --store. Pass --host / VSTACK_HOST the same as a file review.

Get the app running first when it's yours to run. If it isn't up, the canvas says so instead of showing a screen: start the dev server yourself (background), or ask which command does it. --start /workflows opens on a screen other than the front door. A public site needs none of that — point at it and go.

What changes

  • Every comment carries the route it was made on. Marks are drawn only on that screen; elsewhere the comment sits in the list tagged another screen, with the route under it, and clicking it takes the frame there. The reviewer clicks through the app to reach a screen, or types a path in the address bar. So a review can span the whole flow in one pass — the brief comes back grouped by screen size, each comment naming its Route.
  • A version is a marker, not a file. publish --name <slug> --label "…" --close … records what you finished; there is no snapshot of a file because the app is the truth. The timeline still scrubs: the workspace captures the DOM of the screen they were commenting on each time they send, so history shows what they were looking at when they said it.
  • You change source, not markup. Go from a comment to the code through its anchor: the element's id, its distinctive classes, and above all the words on it — text and label are usually a literal string in the component. Search for those first, then confirm with the route. Say which files you changed when you reply.

If the app hot-reloads, the reviewer watches your change land. That is an argument for landing whole changes rather than halves, not for working slower — and the delivery loop (§5) still matters, because a review of a live app can be stopped mid-flight just as easily.

If the project has tests

A live review changes source, so a project with a test suite has one to keep green. Comments arrive one at a time and the reviewer watches a progress bar on each until you answer it, so a full run per comment puts the suite in front of every mark.

  • Per comment, run only what your change touches. For a spacing, wording, colour or ordering change that is usually nothing, and skipping is the right call. Say you skipped it rather than leaving the user to assume a run.
  • Run the full suite when the queue drains — unanswered clean and status showing no comment queued. The reviewer is reading your round then, so the run costs them no waiting.
  • Fix a failure the full run finds before you take the next comment, and say in chat which comment caused it. The comment it came from is already closed, and it does not reopen.

A file review (§1–§6) changes one self-contained HTML file, so none of this applies to one.

A public website works too

Same command, a real URL:

node "$SKILL/assets/review-server.mjs" serve --app https://example.com --name marketing --port 7788

A site published on the internet writes its own origin into its markup, so the proxy rewrites text responses to point back through itself — otherwise the first link the reviewer clicks takes the frame off the proxy, cross-origin, and every comment silently stops working. It also strips HSTS, drops the Domain off cookies so a session survives on localhost, decompresses what it has to rewrite, sends the site its own Origin and Referer, and refuses service-worker registration so a site cannot take over the origin the workspace lives on.

What that buys: a whole marketing site, a competitor's flow, a production app — clicked through and commented on screen by screen, with each comment naming its route.

  • Check the front door first. If the target redirects to another origin (the www host is the usual one), the server says so on start and names the URL to use instead. Review the origin they actually land on.
  • A comment on someone else's site is a note about a design, not a licence to copy it. Layout and interaction patterns are fair to learn from; logos, wordmarks, photography and copy are not — they stay placeholders in anything you build from it (§2a).
  • Off-site links leave the review. The workspace says off-site in the address bar and offers Back. Nothing on another origin can be read or annotated — that is the browser's rule, not a gap.

What it cannot do

  • Bot protection and CAPTCHAs stand. Cloudflare-style interstitials, rate limits and bot checks apply to the proxy like any other client, and are not to be worked around. If a site refuses to load, say so and stop.
  • A login wall needs the user. Never enter credentials. Ask them to sign in themselves in the workspace's window — the session lives on the proxy's origin, so they log in there once even if they are already logged in elsewhere — then carry on.
  • Strict CSRF or origin checks can still refuse a POST, and an API on a third origin that only allows the site's own will refuse the browser. Reads are reliable; writes on a hardened site may not be.
  • A live review has nothing to publish. Publish a link is not offered: what is under the marks is an app running on this machine, not a design that can be sent. If they ask for one, say that, and offer a screenshot (Host op browser_capture) instead.

Notes

  • Never edit assets/workspace.html, review-server.mjs or bundle-artifact.mjs to fit a project — they're the engine; only the page under review is yours. The shell chrome is stamped in from lib/shell/ — see lib/shell/README.md. (harvest-reference.js is meant to be pasted and run, not edited.)
  • State lives in <dir>/.vstack/local/review/<name>/ beside the file — versions, reviews, threads, and the sentinels. The page itself stays clean. A live review has nothing to sit beside, so it lands in .vstack/local/review/<name>/ under the directory you started it from.
  • Every vstack tool writes under .vstack/local/<tool>/, so a project grows one dot-directory, not one per engine. lib/workdir.mjs resolves it — use that rather than joining the path by hand. One gitignore line covers the lot (**/.vstack/local/); the rest of .vstack/ is the pipeline and belongs in the repo.
  • The server binds to 127.0.0.1 only. Port 7788 busy usually means a review server is already running — pass --port.
  • node "$SKILL/assets/review-server.mjs" status --file "$FILE" prints the current version, whether a review is waiting, and any sign-off / share request outstanding.
  • Every command takes --name <slug> in place of --file for a live review — publish, reply, share, status, watch. The brief tells you which name to use.
  • Full command reference and troubleshooting: references/workflow.md.
  • Contracts: plugins/vstack/contracts/ — Host ops and review-loop protocol.
  • Host adapters: skills/review/hosts/claude.md, skills/review/hosts/codex.md, skills/review/hosts/grok.md.

State & handoff

No .vstack/pipeline.json? You're standalone, and that is a first-class way to run this — a URL or a sentence is enough. Everything above still applies; skip this section. Never create the state file here — a half-written one is worse than none, because the next stage would trust it. Nothing currently shipped brings a pipeline into being: the tool that did, start, is parked in plugins/vstack/experimental/. Standalone is the normal case.

Standalone, the design source is §2's priority order (reference site → screenshots → the project's own system → ask), the page goes where the user wants (default wireframes/), and you end with the result. Do not propose another Visual Stack tool; wireframing is the complete product workflow.

With a state file:

  • Read artifacts.product — specs/product.md is the constitution, and a wireframe that contradicts it is wrong however good it looks. Read artifacts.requirements if it is there. In a repo from the template, design/tokens.css and design/CLAUDE.md are the design source and outrank §2's order — you are drawing inside a system that already exists.
  • Write the page to design/<feature>.html — the template's convention, and where the later stages look. Then artifacts.wireframes[]: append for a new feature, replace in place for one already there, matching on feature and never on array position. Set stage: "wireframe" and add a history entry. If the template's design/README.md inventory exists, fill the feature's row.
  • Write it on sign-off, not on every publish. A design still under review is not an artifact; recording it as one puts versions in the state file that nobody agreed to. Approve is the moment.
  • A live review produces no wireframe artifact. What it changes is the code, which the repo already records — so do not append to artifacts.wireframes[] for one. Say what you changed and leave the pipeline alone; the design stage is about designs that do not exist yet.
  • On sign-off, report the approved wireframe and end the workflow. Do not hand off to another Visual Stack tool unless the user explicitly asks for one by name.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

go

無料

Compatibility entry for Visual Stack's former /vstack:go command. Runs the wireframe and UI review tool, now called review. Use only when the user invokes /vstack:go.

日本語の概要は準備中です。原文の説明を表示しています。

Cavalry-Collective/visual-stack112026年10月10日 更新

Build one release phase against the specs — plan it on an interactive board (endpoints, components, resources, with what already exists read from the codebase), let the user adjust, then build node by node while the board shows live progress. Use when the user wants to build a phase, implement the phase-1 slice, execute the plan from a story map or spec, or watch a build happen visually.

日本語の概要は準備中です。原文の説明を表示しています。

Cavalry-Collective/visual-stack112026年10月10日 更新

Preview a signed-off design one release phase at a time — cut it down into a series of phase screens, each showing only what exists by that phase with the layout untouched, then put them on a scrubber you drag to watch the screen fill in release by release. Use when the user wants a Phase 1 / MVP version of an existing wireframe or mockup, phased or staged screens, a design sliced by release phase or story map, or wants to see what a screen looks like before later features land.

日本語の概要は準備中です。原文の説明を表示しています。

Cavalry-Collective/visual-stack112026年10月10日 更新

spec

無料

Turn a wireframe and everything already agreed into a written spec in traditional agile shape — an initiative broken into epics, epics into user stories with acceptance criteria, and themes as the labels that span them — presented as an interactive drill-down tree the user prunes, edits and annotates in the browser, with a plain-markdown spec generated from it. Use when the user wants a spec, an initiative or epic broken into user stories, acceptance criteria, to formalise what a wireframe or mockup does, or to review and edit a spec visually.

日本語の概要は準備中です。原文の説明を表示しています。

Cavalry-Collective/visual-stack112026年10月10日 更新

start

無料

Start a project on the Visual Stack — a multi-step setup form captures what's being built, recommends a stack, and either instantiates the vstack-template-base template, sets up a specs-and-design-only workspace, or records an existing codebase without touching it. Use when the user wants to start a new project, scaffold a repo, set up a codebase from the Cavalry template, pick a stack or add-ons, run Day-1 setup, or bring an existing app onto the visual stack.

日本語の概要は準備中です。原文の説明を表示しています。

Cavalry-Collective/visual-stack112026年10月10日 更新

Build an interactive, drag-and-drop user story map so the user can re-slice work across release phases. Use when the user wants a story map, a phased roadmap, release slicing, a backbone/activities journey map, or to decide "which stories go in which phase" and move them around.

日本語の概要は準備中です。原文の説明を表示しています。

Cavalry-Collective/visual-stack112026年10月10日 更新

Cavalry-Collective のスキルをすべて見る

このスキルの問題を報告する