@sal7one/dsh-design-studio
A DeepSeek Harness plugin that turns design mockups into a first-class AI workflow.
Live previews, an element picker, a real design agent, vision review, identity presets —
and a two-agent apply flow where DeepSeek edits and the design agent verifies.
Everything is backed by real files in the current workspace under
design-studio/, and the install is launch-persistent: install once, the
Design Studio tab is there on every launch.
Screenshots
Click any screenshot for the full-size image.
DSH-Design-Studio/
├── package.json # dual-face manifest: dsh.bundle (host) + dsh.client (web UI)
├── cordis.patch.yml # the composition layer this bundle contributes
├── README.md # this file
├── CHANGELOG.md # release notes (2.3 atlas, 2.2 history, 2.1 split/settings)
├── LICENSE # MIT
├── THIRD_PARTY_NOTICES.md # style-atlas attribution and MIT notices
├── icon.svg # plugin inventory artwork
├── locale/ # plugin inventory display metadata (en/zh)
├── repo-images/ # UI screenshots shown at the top of this README
├── lib/
│ ├── data/
│ │ └── style-atlas.json # attributed 88-style snapshot (no runtime dependency)
│ ├── index.js # host orchestrator: design systems, agent, HTTP route + tool
│ ├── host/ # host domains
│ │ ├── constants.js # shared limits, key reference, slug regex
│ │ ├── util.js # pure helpers: zip writer, paths, base64, PNG size
│ │ ├── node-io.js # Node helper seam, binary writes, delete, browser capture
│ │ ├── config.js # config load/save, key info, harness vision detection
│ │ ├── vision.js # harness + OpenRouter review, image descriptions
│ │ ├── preview.js # headless preview snapshot
│ │ ├── presets.js # identity preset CRUD + apply
│ │ ├── assets.js # asset manifest, sha256 dedupe, upload/import/delete
│ │ ├── history.js # content-addressed blobs, trees, snapshots + restore
│ │ └── styles.js # style atlas apply/save/create + CSS token generation
│ ├── client.js # GENERATED self-contained ModuleLoader bundle (shipped)
│ └── client/src/ # runtime, styles, labels, primitives, api, element-picker,
│ # scaled-preview, assets-modal, history, style-atlas,
│ # studio-view, settings, index
├── scripts/
│ ├── check.mjs # dependency-free release/check script
│ └── bundle-client.mjs # source → lib/client.js; installs never run it
├── tests/ # host + client smoke tests (node --test)
└── examples/ # example design systems (html/css/js mockups + presets)
✨ Features
Core platform
- One command, persistent — a dual-face
dsh.bundle + dsh.client package:
dsh plugin add once, and the tool, the preview route, the prompt section and the
Design Studio tab are present on every launch. No install-time build step, no
TypeScript, zero runtime dependencies (plain JavaScript); the client source split
is bundled ahead of release into the committed lib/client.js.
design_studio agent tool — your assistant (and any subagent) can
list / all / create / read / write / zip / reveal / delete / sweep design systems,
manage business pages (page_list / page_create / page_rename / page_delete),
manage assets (asset_list / asset_upload / asset_import / asset_delete), save and
restore edit history (history / snapshot_save / snapshot_restore / snapshot_undo),
apply/save/create styles (style_list / style_apply / style_save / style_create),
manage identity presets, run vision reviews, chat with the design agent, read its history,
and configure the studio — design files live in the workspace
design-studio/<slug>/ folder (legacy profile designs remain readable).
- Optional Compose Desktop target — point
app.project at a Compose Multiplatform
project that exposes Compose Hot Reload's hotMcpServer (CMP 1.12+) and the App
tab drives the real app: start, reload, screenshot, semantic tree, logs. No Gradle
wrapper or no project means it stays off, with an honest empty state. See
docs/compose-desktop.md.
- Android app target (Appium) — bind one design project to an already-built
Android app and the App tab drives it through Appium: live screenshot and
uiautomator2 tree, hover-before-click highlighting, a selection popup with a
change-request field, and one-click capture into the project's assets and
edit history. The Connect popup stores the app package/activity plus the
project root, Gradle build task and APK path, so an agent can rebuild and
reinstall the same existing project after a request. It also indexes the
project's static navigation routes and maps a selected test tag back to its
source definition and other usages; screen identity comes from
SCREEN_*
tags. The session survives tab switches via a host keepalive and reconnects
automatically. See docs/android-app-targets.md.
Design systems
- Mockup-scoped files — every design system is
html/index.html,
css/style.css, css/token.css, js/app.js (minimal presentation) plus
design_prompts_forcoders.md (the brief the coding agent follows) and
assets/images/ for uploads. Mock data stays honest — empty/loading states,
never fabricated live numbers.
- Per-conversation ownership — each design system is bound to the conversation
that created it; the tab shows only your chat's designs (unbound legacy systems
are adopted on first list).
- Drop zones + asset library — drop images or code files onto the tab; images land
in
assets/images/ and auto-select in the agent chat picker. The 🗂 Assets modal
uploads by drop/picker, dedupes by sha256, records MIME/dimensions/bytes/alt in
assets/assets.json, and offers thumbnails, a lightbox, copy-path/copy-<img>, and
delete. asset_import can pull an operator attachment path directly. Preview captures
are excluded from the library.
- Attributed style atlas — 88 styles plus their theme palettes and font moods adapted from
dsh-ui-ux-pro-max (MIT; see THIRD_PARTY_NOTICES.md).
The Styles tab is a gallery grid with a large Try them now action. That
opens a horizontal style tour over the current design: arrows or
←/→ auto-try
each style live, a scrollable strip jumps anywhere, and Apply/Revert are one
action away. The tour sits above the preview and scrolls only its own strip. The
gallery also offers filters/search,
random-next, a pre-style snapshot with Undo apply, full-template New,
and “Save current” into a reusable custom style. Auto snapshots follow AI edit
batches and design-agent turns.
- Content-addressed edit history — every design gets a snapshot tree under
_studio/history/<slug>/: sha256 blobs, sorted tree manifests, and parent-linked
snapshots with a head cursor. Auto-capture runs after edits settle; the History
tab offers manual checkpoints, undo-last-edit, and restore-to-snapshot. Restoring
moves the head without deleting later snapshots, so earlier states stay restorable.
- Cross-platform zip export + reveal + delete — a built-in store-only ZIP writer
(no
zip binary), the OS file manager (open -R, Explorer, xdg-open), and
recursive delete without a POSIX shell.
Design agent (real harness subagent)
- It does the work itself — the agent chat spawns a harness subagent through
ctx.subagents.startActivation (design-studio persona, delivery: 'caller',
cwd set to the design system, maxDepth: 1 — the child is depth 1, so it
runs but cannot spawn grandchildren) that lists, reads and edits the
design files across multiple tool calls per message, then summarizes file-level changes.
- Live activity — its reads/edits stream into the chat as they happen, with
inline errors, a persisted per-system history, and run timeouts.
- Vision, harness first — when the current harness model advertises image input
(reported by
action config → harnessVision), images explicitly selected in the
picker (or mentioned by filename) are attached directly to the child prompt, so
the design agent inspects the pixels itself. Only when the harness model cannot accept
images does the plugin fall back to OpenRouter descriptions.
- Design-cache discipline — on every turn (even a bare "ok") the agent verifies
the freshness stamp, reports whether the design changed since its last turn,
adopts the latest files as truth, and asks what you want when the request is vague.
🎯 Element picker + two-agent apply flow
Click 🎯 Select, click any element in the live preview, describe the change:
| Button | What happens |
|---|
| 🤖 Ask DeepSeek (default) | Saves EDIT_REQUEST.md, sends the request to your main chat through the retained Session binding (session.prompt(..., 'queue')). DeepSeek edits the files itself and invokes the design agent only when it needs a visual read. A live run banner tracks queued → working → finished in the tab, and the studio auto-runs a design-agent verification once the edits settle. |
| ◈ Make the design agent do it | The classic flow: the design agent applies the change itself and replies in its chat. |
| 💾 Save only | Just writes EDIT_REQUEST.md — apply later from either chat. |
- Design switcher — the workspace bar in every tab (including Preview) lists
all designs and marks frozen ones with 🔒. Switching reloads that design's
preview, files, history, assets, styles and freeze state. Studio-wide settings
(vision, capture size, agent preset) remain global.
- Multiple pages per design — one design can hold several business pages,
shown together in the Pages artboard canvas and switchable from Preview.
Pages live at
pages/<id>.html with shared css/token.css and assets; a page
has its own css/pages/<id>.css, js/pages/<id>.js and optional
css/pages/<id>.tokens.css. Page-scoped style applies (Styles → This page)
write the page token file; Entire design writes the global css/token.css.
Sidebars, drawers, modals, tabs and filters are overlay states on the same
page — not new pages. Use a fixed overlay layer with a blurred/inert backdrop.
Add pages only for a new business screen/flow. Zip, freeze, history and delete
cover every page automatically because they work on the whole design root.
Design freeze (design → implementation handoff)
- A large ❄ Finish & freeze design button marks a design system as the
read-only source of truth. Freeze captures a final snapshot, refreshes the zip,
and records an implementation target (defaults to the current project;
the selector also lists other live chat projects, workspaces that already
contain designs, and recent freeze targets, with a custom-path fallback) plus
an optional handoff note.
- While frozen,
design_studio rejects write/style/asset/history-restore/delete
and design-agent actions; read, snapshot, review, zip, and open still work.
list/all return frozen and the freeze record so every agent can see it.
- The UI shows a Design frozen — implementation mode banner and disables
edit controls. Only an explicit Thaw design confirmation re-enables edits.
- Agent guidance lives in AGENTS.md,
skills/design-studio/SKILL.md, and the
handbook: frozen means work in the
implementation target, not the mockup.
- Built-in routing: the plugin injects this workflow into the DSH system
prompt. Operators do not need to write “build the mockup only”, “when I say
freeze…”, or “implement the frozen design” on every project. Approving with
done / looks good / LGTM / freeze is enough; freeze defaults to the current
project.
- Completion gate: when the design is ready, the agent asks one native
question with three choices — Keep refining, Freeze only, or
Freeze & implement — then acts on the answer. It asks once per completed
revision, not after every tiny edit; after a refinement it asks again with the
native tool instead of falling back to plain chat.
Freshness stamps (multi-agent safety)
- Every design change bumps a stamp
{hash, at} (fresh random hash + ISO time,
latest-status only) — the plugin detects changes from any editor via the
harness fs/observed stream, plus synchronous bumps on its own write paths.
Path comparisons are Windows-aware (the old code compared / prefixes only).
- Agents compare their remembered hash with the current one: drift ("changed since
your last turn") is surfaced in prompts and tool output, and the design agent
records a per-turn design cache so the next turn can prove UNCHANGED/CHANGED.
Vision & preview
- 👁 Review — honest
GOOD | POOR verdict + one-sentence notes against the brief.
The plugin asks ctx.llm.resolveModelInfo whether the current model accepts images;
when it does, the review runs on the harness route with no OpenRouter key
(transport: harness). visionTransport can be auto (default), harness (no
fallback), or openrouter (always use the key).
- 📷 Capture — a headless Edge/Chrome renders the actual served preview to a PNG
(
assets/images/preview-*.png) and returns it as an attached image. The model can
see the rendered design directly instead of guessing from source. The same capture
feeds review and the design agent. If no Chromium browser is installed, the action
reports that honestly; the rest of the studio still works.
- OpenRouter fallback — when the harness model does not accept images, reviews and
image descriptions use the configured OpenRouter models through Node's built-in
fetch (no curl, no temp files). The key is a harness credential reference
(OPENROUTER_API_KEY) and is never rendered or returned.
- Identity presets — save palettes/typography/logos as presets;
preset_apply
writes css/token.css and copies logo assets.
Settings & data
- Settings → Design Studio — a single DeepSeek settings entry with internal
Preferences and All designs tabs. Preferences covers vision transport,
review style, default style apply scope, reasoning effort, capture viewport,
agent preset, auto-verify, lifecycle and advanced presets. All designs is a
grouped workspace library with search, status filters, counts, latest ZIP
dates and preview/zip/show-in-folder/delete actions.
- Everything survives restarts — designs live on disk in the workspace
design-studio/; presets, config, reviews and agent history stay in the profile.
Agent knowledge and skill
For agents working in this repo, Design Studio now has a repo-local handbook and
skill. These are not installed into the DSH profile yet; they are source
material for future distribution.
Quick start
Works with both harness distributions — the npm distribution
(npx @deepseek-ai/dsh web) and a Desktop/source checkout.
Install from npm (recommended; no git network dependency)
Once the package is published:
dsh plugin --profile desktop add @sal7one/dsh-design-studio
Or from the Web Plugins page (the bundle is publishable and declares
dsh.bundle.patch, dsh.manifestVersion: 1, engines.dsh, display metadata and
an icon). Restart the harness after installing if your profile has no HMR.
Install from git
dsh plugin --profile desktop add git+https://github.com/Sal7one/DSH-Design-Studio.git
The package has no prepare/build script, so pnpm has no build permission to
prompt for. It only needs GitHub to be reachable during the fetch/install.
Install from a local checkout
dsh plugin --profile desktop add "link:/absolute/path/to/DSH-Design-Studio"
On Windows, link:S:/projects/dsh/DSH-Design-Studio is the equivalent. Use an
absolute path: a bare relative path is read as a GitHub owner/repo shorthand.
Remove with the package name:
dsh plugin --profile desktop remove @sal7one/dsh-design-studio
The bundle row is enabled by default. To keep it installed but off, override it in
your profile's own cordis.patch.yml (profile layers apply after bundle layers and win
per row):
- id: dsh-design-studio
disabled: true
Optional: an OpenRouter key is only needed as a fallback when the current harness
model does not advertise image input. Run design_studio → config; if
harnessVision.available is true, reviews and selected images use the harness model
directly. The key is stored via the credential seam and never shown again.
Plain-English setup (non-power users)
- Install Node.js (v22 or newer) from nodejs.org.
- Start the harness:
npx @deepseek-ai/dsh web
A browser window opens at the harness URL it prints (usually a loopback
address such as http://127.0.0.1:<port>) — that's the harness Web UI.
- Install this plugin:
dsh plugin --profile desktop add @sal7one/dsh-design-studio
- Restart the harness (Ctrl+C, start again). The Design Studio tab now
appears in every conversation, plus a single Settings → Design Studio entry.
- Design something. Create a design system, or just describe a screen to the
assistant — it routes briefs into the studio automatically. The live preview is
served at
<harness-origin>/design-studio/<name>/html/index.html (the exact
origin is the one printed by the harness).
Workflows
Design → freeze → implement. Describe the mockup. The plugin's injected
routing keeps the agent in design mode until the design is approved. When it
thinks the design is ready it asks one native question: Keep refining,
Freeze only, or Freeze & implement. Freeze defaults to the current
project. “LGTM / looks good / done” freezes directly; “freeze and implement”
does both without another confirmation.
Iterate with the design agent. Open the Design Studio tab → select your design →
type a request in the agent chat ("make the status bar left-aligned", "use this image
as the background"). It reads, edits and summarizes; the preview reloads.
Pick an element and let DeepSeek change it. 🎯 Select → click the element → type
the change → Enter sends it to Ask DeepSeek (Shift+Enter adds a line; Save only
writes the request without sending). The request appears in your main chat, DeepSeek
edits, the tab banner tracks progress, and the design agent auto-verifies the result.
Give DeepSeek a visual job. Drop a palette image on the tab (it lands in
assets/images/), then in the main chat:
In the tic-tac-toe design, read the color palette from assets/images/palette.png
and apply it to css/token.css. Use the design agent for the visual read.
DeepSeek routes the visual work to the design agent (design_studio → agent), the
image is auto-attached and vision-described, and the result flows back into DeepSeek's
tool result.
Requirements
- Node ≥ 22 and a harness on the 0.2.x line (
engines.dsh:
>=0.2.0-rc.2 <0.3.0; tested on 0.2.1-rc.2) with the standard host services
(fs, subprocess, webServer, llm, credentials, attachments,
systemPrompt, tools, plus optional agents/subagents for the design-agent chat).
- The workspace
design-studio/ folder is created automatically on first use;
legacy profile designs remain readable. No symlink or manual setup is required.
- For vision: a harness model that advertises image input (preferred; no extra key),
or an OpenRouter key under credential reference
OPENROUTER_API_KEY as the fallback.
- For 📷 Capture: a local Microsoft Edge, Google Chrome, or Chromium install.
It is optional; the rest of the studio works without it.
- For Android app targets: Appium 3 with the
uiautomator2 driver on
loopback (127.0.0.1:4723), an installed debug APK, and a visible
emulator/device. Building and installing the app itself needs the project's
JDK + Android SDK; the plugin never runs Gradle.
Storage and upgrades (2.7.0)
- New designs:
<workspace>/design-studio/<slug>/. These are ordinary
workspace files and can be committed, reviewed and edited under the normal
sandbox. They are visible in every conversation rooted at that workspace, not
just the creating chat.
- Pages: the first page is the existing
html/index.html. Additional pages
are pages/<id>.html with css/pages/<id>.css, js/pages/<id>.js and
css/pages/<id>.tokens.css; _studio/pages.json is the manifest. They share
the design's css/token.css, css/style.css and assets/. ZIP/freeze/history
and design delete operate on the whole design root, so all pages are included.
- Profile:
temp_design_folder/ still holds global config, presets, the
slug registry, and legacy designs created before 2.7.0.
- Legacy designs are not auto-migrated. They remain readable and editable
from the Studio, but a workspace-only agent may not have filesystem access to
the profile path. New work should use a new workspace design.
- Slug collisions: a slug is unique across the profile registry and legacy
designs. Creating the same slug in another workspace is rejected. Use a
unique slug, or migrate the legacy design deliberately.
- Preview resolves the design's registered root, so
/design-studio/<slug>/
works for both workspace and legacy designs.
Security model
Design Studio is a local, operator-trusted tool.
- The HTTP API is loopback-only and unauthenticated. Do not expose the harness
port to a network.
- The preview iframe is same-origin and deliberately unsandboxed so the element
picker can inspect the design DOM. A mockup’s HTML/JS is therefore executable
code with same-origin access; only open designs you trust.
asset_import accepts local source paths. Treat the Studio API as equivalent
to local file access.
- Freeze is a tool/context guard, not an OS ACL. Direct file writes are outside
its control.
- The workspace write fallback uses the Node write seam when the host fs policy
denies a design path; it is restricted to the active design root.
Issue #1 — install/distribution failure (closed)
The original report tried:
dsh plugin --profile desktop add git+https://github.com/sal7one/dsh-design-studio.git
and failed at commit c08abef with git fetch exit 128 /
LibreSSL SSL_connect: SSL_ERROR_SYSCALL. Three separate layers were involved:
- The package was not publishable. That commit still had
"private": true
and was not on npm. This is fixed: private is removed, the package is public,
and it has publishConfig, files, engines.dsh, dsh.manifestVersion and a
tag-driven publish workflow.
- The hub's registry search query is unsupported.
npm search repository:sal7one/dsh-design-studio does not search the repository field
in npm metadata, so it returns nothing even though
@sal7one/dsh-design-studio is published. This is a hub-side bug; the
workaround is to search/install by package name:
npm search sal7one or dsh plugin --profile desktop add @sal7one/dsh-design-studio.
- The git fetch itself hit a TLS/network failure to
github.com:443 on that
machine. The current package has no prepare script and no install-time
build, so a working GitHub connection needs no allowBuilds permission;
npm install avoids git entirely.
The current repository is public, publishable and installable from npm. Verify
the published artifact with npm view @sal7one/dsh-design-studio version; the
npm package name is @sal7one/dsh-design-studio, not a repository-search hit.
The hub-side search bug still needs reporting to the hub; installing by package
name bypasses it.
⚠️ Compatibility notes — current harness contracts
This plugin was built and broken against a moving harness base. The traps that remain
relevant:
- The design agent uses
startActivation, not start. The current contract is
ctx.subagents.startActivation({ provider, label, request, signal, delivery });
the request carries prompt, parent, cwd, signal and maxDepth. The old
.start(provider, { persona, … }) call silently failed on 0.2.x.
- A live session is a live Agent, and its id is
agent.id. The host-level
sessions service no longer exists; orphan detection reads ctx.agents.list().
Tool handlers must read exec.agent.id, not the removed exec.agent.sessionId.
- Client modules must inject real client packages and load immediately.
dsh.client.inject now names @deepseek-ai/dsh-client-ui-conversation,
…-ui-settings, …-ui-session and …-locale; immediately: true makes the tab
register at boot. The removed @deepseek-ai/dsh-client-runtime entry is gone.
conversation.view hands sessionId as a standard prop. The obsolete
registration inject: (sessionId) => ({ sessionId }) face was removed; the view
reads props.sessionId directly.
- Send to the main chat through
SessionFace.prompt. The scoped
conversation.send path is gone; the tab uses
sessions.binding(id).session.prompt([{ type: 'text', text }], 'queue').
- No shell assumptions. The host builds shell semantics itself only where it
still needs the subprocess seam (Node helper for binary writes/deletes, OS file
manager for reveal). ZIP export is a built-in store-only writer. This is what makes
the plugin work on Windows.
- Commit
lib/. A harness checkout's .gitignore ignores lib/ — a plugin
committed inside one ships without its entry point. This repo lives at its own top
level and ships plain JS, so lib/index.js is committed.
- Hard-inject host services you register against.
apply() runs as soon as its
injections resolve; webServer, systemPrompt, tools, etc. must be in inject
so the route/tool/section registration cannot be silently skipped.
- Vision is route-dependent, not plugin-assumed. The studio asks
for the current selection's and only
then sends s. on this harness reports
, so reviews and selected images run on the harness with no
OpenRouter key. A text-only route falls back to OpenRouter;
() can force either path.
Development
The host is plain ESM under lib/host/; the client source is split under
lib/client/src/ and bundled into the committed lib/client.js (installs never run a
build). Regenerate the bundle after client edits:
npm run build:client
npm run check # fails if lib/client.js is stale
npm test
npm pack --dry-run
The tests use a virtual fs and a fake host context, so they run without a live
harness. The client test loads lib/client.js through the module loader in a VM and
asserts the three slot registrations plus style cleanup.
Publishing
The package is publish-ready and has no install-time build step; lib/client.js is
committed in generated form:
npm publish --access public
Or push a version tag (v2.8.0); .github/workflows/publish.yml publishes to npm
using the NPM_TOKEN repository secret. .github/workflows/ci.yml runs the same
checks on pull requests and pushes.
Before tagging, verify the release smoke path:
npm run build:client && npm run check && npm test
npm pack --dry-run
npm pack contains lib/host/pages.js, scripts/, AGENTS.md, the handbook,
and no tests, research, or local design-studio/ data.
- A throwaway design:
page_list → page_create → style_apply scope=page →
zip → inspect the zip for pages/<id>.html, _studio/pages.json and page
CSS/JS → page_delete.
- README screenshots use unique filenames and absolute raw URLs. The local
v2.8.0 tag must match package.json; the workflow rejects a mismatch.
Then PR one entry into awesome-deepseek-harness (alphabetical, one PR per change,
carry the #dsh-plugin topic for discovery).
License
MIT
The style-atlas data is adapted with attribution from
dsh-ui-ux-pro-max (contributors) and its upstream
ui-ux-pro-max-skill (Next Level Builder), both MIT.
See THIRD_PARTY_NOTICES.md.
Changelog
2.8.0 — Android app targets and Compose Desktop. Bind a design project to
an installed Android app and drive it through Appium from the App tab:
live screenshot/tree, hover highlighting, selection popup, project-root/build
fields, capture into assets + history, and a keepalive session that survives
tab switches. Also ships the optional Compose Desktop target. See
docs/android-app-targets.md.
2.7.7 — larger canvas and project style scope. Preview opens at 1:1
(large design area, scrolls) with Fit available. Style apply defaults to the
project/all-pages scope, configurable in Design Studio settings. All designs
lives inside Design Studio as an internal tab, grouped by workspace with search,
status filters, counts, latest ZIP dates, and clean
preview/zip/show-in-folder/delete actions. Settings now makes unsaved changes
explicit and keeps its Save/Refresh header aligned.
2.7.6 — explicit style apply scope. Style preview and tour actions expose
Apply to this page and Apply to all pages buttons.
2.7.5 — sidebar-safe preview and multi-page canvases. Preview defaults to
Fit with an explicit Fit / 1:1 control; wide 1:1 previews start at the
left edge and scroll horizontally instead of disappearing under the open
conversation sidebar. One design can now hold multiple business pages with a
Pages canvas, page switcher and page-scoped style applies. Sidebars/modals stay
in-page overlays.
2.7.4 — release-review hardening. Local API rejects cross-site writes,
workspace write fallback is root-bound, vision brief overrides work, design
switches reset the run banner, and the publish workflow checks tag/version.
Freeze's project picker now lists other live chat projects and workspaces with
designs. Screenshots now render on npm; the local security model is documented.
2.7.3 — design switcher. Preview now has a Design selector in the
workspace bar for every visible design, with frozen badges; switching reloads
that design's files, history, assets, styles and freeze state.
2.7.2 — workspace designs visible across chats. A design in
<workspace>/design-studio/ appears in every conversation rooted at that
workspace, not just the chat that created it. Legacy profile designs keep
their old per-session behavior.
2.7.1 — repeat the Design ready gate after refinement. Choose Keep
refining, finish the next revision, and the native three-choice question
returns. No plain-chat fallback while is available.