npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@12ui/design

v0.2.132

Published

The canonical 12ui CLI, SDK, MCP server, and visual interface design skills

Readme

@12ui/design

@12ui/design is the canonical 12ui CLI, SDK, MCP server, and agent-skill package. The 12ui binary stays stable while package imports and installation use the new name.

Install with Node on macOS, Linux, or Windows:

npx -y @12ui/design skill install

Or use the genuinely npm-free macOS/Linux installer:

curl -fsSL https://12ui.com/install.sh | sh

Both paths pin the exact CLI version, install 12ui-design into every detected Codex, Claude Code, Grok CLI, Cursor CLI, Antigravity, and GitHub Copilot CLI installation without requiring an API account. Ordinary corpus search and downloads also work without an account. Run 12ui auth login for authenticated hosted generation or explicit hedge search. Explicit authentication setup creates a user-owned credential with design.convert and design.corpus.retrieve, is verified before use, and is stored mode-0600 at $XDG_CONFIG_HOME/12ui/credentials.json or ~/.config/12ui/credentials.json. When those private roots are unusable and TWELVE_UI_CONFIG is not explicit, the CLI stores the credential mode-0600 at $TMPDIR/12ui-<uid>/config/credentials.json, reports the exact path, and labels it as lasting only for the managed environment lifetime. Later commands in that environment rediscover the same file; no credential is written into a workspace.

CLI only, for a shell that does not want the skills:

npx -y @12ui/design cli install
curl -fsSL https://12ui.com/install-cli.sh | sh

Both pin just the 12ui binary - no skills, no browser sign-in - into the same managed launcher and versioned bundle, verified and installed the same way. 12ui cli status reports what is pinned. Managed installations do not update automatically; 12ui cli install pins the version currently running. 12ui update upgrades an installation: it runs npx -y @12ui/design@latest skill install, which pins the newest release and refreshes every skill and plugin skill install manages, then runs claude plugin marketplace update 12ui-plugin and claude plugin update 12ui-design@12ui-plugin in every Claude Code home that has the plugin. 12ui skill install adds the skills later.

Every supported agent reads SKILL.md bundles from one user-scoped directory, so the same bundle is installed byte-identically to each:

| --client | Agent | Installs into | | ------------- | ------------------- | ----------------------------- | | codex | Codex CLI | ~/.codex*/skills/ (CODEX_HOME) | | claude-code | Claude Code | ~/.claude*/skills/ (CLAUDE_CONFIG_DIR) | | grok | Grok CLI | ~/.grok/skills/ (GROK_HOME) | | cursor | Cursor CLI | ~/.cursor/skills/ | | antigravity | Google Antigravity (agy) | ~/.gemini/config/skills/ | | copilot | GitHub Copilot CLI | ~/.copilot/skills/ (XDG_CONFIG_HOME) |

skill install installs into every agent it finds and prints one line per agent; an agent that is not on the machine is reported as a skip, not an error. An agent counts as present when its home directory exists, its executable is on PATH, or its home environment variable is set. Copilot CLI discovered skills from ~/.copilot/skills/ starting in 1.0; releases before that have no skill mechanism at all.

Codex discovery includes every local ~/.codex* profile directory, plus CODEX_HOME when it points outside that set. Claude Code discovery includes ~/.claude, every other ~/.claude* directory that holds .claude.json (Claude Code's own file in each config dir; other tools' ~/.claude* folders are skipped), and CLAUDE_CONFIG_DIR. A profile that is a symlink to a directory counts like the directory. Pass --client codex --home <path> when an operation should target only one profile.

Where the agent can carry the Design workspace as a plugin, skill install installs the plugin, which carries the same skill, instead of the bare skill:

  • Claude Code 2.1.287 or later gets 12ui-design@12ui-plugin from the just-every/12ui-plugin GitHub marketplace (the skill, the hosted 12ui-workspace server and the Design workspace pane). The marketplace is set to auto-update, so Claude Code refreshes the plugin at startup. An older Claude Code gets the skill plus one line asking for claude update.
  • Codex with codex plugin gets 12ui@12ui-local: the skill plus the hosted server that draws the workspace inline. The CLI writes it to ~/.local/share/12ui/codex-plugin/12ui (from codex-plugin/ and skills/12ui-design) and adds that folder as the 12ui-local marketplace. The old directory-listed 12ui-design skill is switched off by marked [[skills.config]] blocks.

A skill-only copy the CLI wrote earlier is removed once the plugin is in place, a re-run changes nothing, and 12ui skill remove (or uninstall) removes the plugin, its marketplace and those blocks as well. The shared Codex plugin folder goes only once no Codex home on the machine still has the 12ui-local marketplace. A plugin step that fails (or an agent command that runs past a minute) leaves that home with the skill instead; the other homes and the exit code are unaffected.

Skill installation does not require an API account or start account onboarding. Explicit authentication options still prepare credentials; hosted commands handle authentication when used. Existing unknown or locally modified skills also fail closed unless --force is explicit.

One visual interface skill

12ui-design is the single design entrypoint. Every client receives the same skills/12ui-design bytes. A new screen or page the user will choose among starts the Design workspace from a brief: the hosted plugin's design.slate.create where the workspace shows in the conversation (the Codex app), else 12ui workspace open --concept "<brief>" --wait in a browser page. The skill also runs 12ui branch execute, 12ui convert and 12ui improve; the CLI owns local and hosted engine selection.

The skill's scene.md guide rebuilds a design image as a live Three.js scene. It runs 12ui convert --engine auto (Codex when it is ready, otherwise the 12ui API) in the background for the static page while the agent models the scene with the local 12ui scene tools (12ui scene --help): camera solve, placement, a starter harness with a bundled three.js, 12ui scene merge to put the converted page into the scene, capture with the managed Chromium, and review sheets. The 12ui scene tools need no account and make no network request.

improve --apply captures the URL and edits the actual repository. Without a target it drafts candidates, stops for an explicit choice, then applies that choice locally. Without --apply, the existing hosted implementation-kit behavior remains. Inspect the real application after editing.

Draft, branch, convert and improve

12ui draft, 12ui branch, 12ui convert and 12ui improve are the primary commands. Each keeps its own saved-run format. convert --engine auto, the default, runs on local Codex when it is ready and otherwise selects the 12ui API before dispatch; a saved run keeps its recorded engine. Local conversion uses native Codex images; --image-backend external opts in to the user's own OPENAI_API_KEY, which alone never selects it. Pass --engine to choose the engine yourself.

Local HTML does not produce LayerDoc. Native design formats and hosted branch assembly remain dedicated conversion workflows. React export is whole-page JSX, not a functional application. Preserve existing run directories and their recorded engine for recovery; importing an output into a workflow workspace does not migrate an in-flight dispatch.

Corpus-conditioned image generation explores visual directions. The selected image then guides editable implementation, with browser inspection against the approved target and focused correction of observed mismatches.

12ui skill status --json
12ui corpus inspire \
  --query "Editorial architecture homepage with warm materiality" \
  --reference-image ./current-homepage.png \
  --out-dir ./references \
  --count 4
12ui draft \
  --concept "Editorial architecture homepage with warm materiality" \
  --reference ./current-homepage.png \
  --retain style \
  --candidates 4
12ui next <run-dir> --wait
12ui branch execute \
  --start <run-dir>/candidates/A.png \
  --concept "Editorial architecture studio site" \
  --scope site \
  --convert html \
  --prototype
12ui next <branch-run-dir> --wait
12ui improve https://example.com/dashboard \
  --direction "Editorial hierarchy, compact controls, quiet blue surfaces" \
  --repo ./dashboard \
  --out-dir ./dashboard-improve
12ui improve https://example.com/dashboard \
  --target ./approved-dashboard.png \
  --repo ./dashboard \
  --out-dir ./dashboard-align
12ui convert <conversion-id> \
  --output html_fixed,pdf,psd,pptx,sketch \
  --out-dir ./exports

draft accepts 2-16 candidates and defaults to four. --reference accepts a local PNG/JPEG/WebP path or HTTP(S) URL, keeps the normal corpus retrieval, and sends the original image to every hosted candidate. Its new-page default retains style while excluding layout, content, and assets; --retain layout is the explicit source-geometry opt-in. It records the corpus set, hosted run id, stable service slots, output paths, and claim key in draft.json before dispatch. Every dispatch request stays in the foreground and posts only slots whose durable service state is still pending; in-flight, succeeded, and failed slots are never posted again. 12ui next <run-dir> --wait repairs only never-started slots, then polls and downloads. Successful PNGs are digest-checked and written atomically under <run-dir>/candidates/, with terminal evidence in draft.complete.json.

12ui draft never inspects Codex authentication, OPENAI_API_KEY, project .env files, or another caller-side image-provider credential. This describes 12ui draft, not the workflow ledger's draft recipe.

convert <conversion-id> downloads one successful base LayerDoc once and dispatches the chosen formats concurrently. It creates the destination directory as needed, but refuses before any API request when a selected output, its asset directory, or export-manifest.json already exists.

capabilities --json reports the CLI's exact inputs and outputs, model and responsive-quality choices, duration hints, status commands, and durable journal/receipt contracts.

The local workflow ledger

The CLI also keeps a persistent local workflow ledger, a secondary surface shared by the local CLI and MCP for hosts that drive individual operations themselves:

12ui workflow import /absolute/path/reference.png --workspace ./design-work --role reference
12ui workflow prepare ./request.json --workspace ./design-work --key homepage-direction-a
12ui workflow execute <operation-id> --workspace ./design-work --providers session --session-capabilities text
12ui workflow register <operation-id> --workspace ./design-work --attempt <handoff-attempt-number> --result ./result.json
12ui workflow status <operation-id> --workspace ./design-work

The import source is absolute in this example. Relative imported file paths are resolved inside the workspace: ./reference.png would mean ./design-work/reference.png. Request/result JSON command arguments are read relative to the shell's current directory; file paths inside those results and recipe image paths are workspace-relative unless absolute.

request.json names a capability, prompt, imported input artifacts and output contract. A host session takes only text or code: the execute result is then a handoff, and the session registers its real files or JSON value. Image, image-edit and convert work never goes to a session; the 12ui CLI runs it through its own providers. Preparation, imports and registration do not need a 12ui account. 12ui workflow --help documents the complete contract, provider policy and interruption behavior.

Provider routing considers a host session that declared text or code first, then eligible Codex and Claude subscription CLI capabilities, then the OpenAI API when the user opts in, then the 12ui API on the 12ui sign-in. Image, image-edit and convert work never routes to a session. Codex text/code subprocess execution requires --trust-codex-config: explicit trust in the existing user's CLI configuration, including tools and hooks beyond the command sandbox. This does not opt in to the OpenAI API and does not apply to the current session's tools. Claude requires supported safe mode, edits code with a fixed file-tool set without shell tests, and currently cannot attach images to text requests. Run checks in the parent session. Image capability is never inferred from a text CLI's presence. Session capabilities (text or code) must be explicitly declared from available tools. 12ui credit use needs no permission. The OpenAI API spends on the user's own key and runs only with --allow-paid openai; key presence alone never enables it. An ambiguous dispatched operation requires reconciliation and cannot silently replay on another provider. An accepted job with a failed download, or a completed response with malformed output, stays in reconciliation under the same operation and attempt. Recover and register the original output and dependencies; do not regenerate it. Refusals and permission denials remain terminal stops.

OpenAI requires an explicit model through request parameters.model, OPENAI_MODEL for text/generated HTML, or OPENAI_IMAGE_MODEL for images. OPENAI_API_KEY and TWELVE_UI_API_KEY make separately funded routes discoverable; they never belong in request or result JSON. Native execution removes provider-key overrides from the child environment and uses the user's normal CLI configuration.

The recipes draft, branch, edit, redesign, labels, review, convert and implement build requests for this shared ledger. They do not imply that every hosted pipeline or native design export has a local implementation. After registering a recipe plan, 12ui workflow continue <operation-id> --workspace <directory> prepares eligible child operations without inference; execute each returned ready ID explicitly, then continue the same plan to unlock dependencies. workflow fail records actual refusal, no-output or ambiguous-outcome evidence; it does not turn an uncertain dispatch into permission for another call. Both registration and failure must name the handoff's attempt number so delayed results cannot settle a later attempt. For project implementation, the service captures a baseline before execution. Register the normal report and any real additional receipts; registration derives verified changed-file artifacts and project evidence from the actual selected project. A provider receipt or claimed no-op cannot complete implementation: no changed files produces project_no_changes. File changes and caller-reported browser/test evidence remain separate facts. The ledger records returned artifacts; independent browser/image inspection still establishes fidelity, ownership and behavior. Local execution consumes user model allowance or authorized API budget and local hardware, rather than making model execution free.

workflow capture <http-or-https-url> --workspace <directory> uses local Chromium and a fresh unauthenticated browser to retain screenshot, DOM and redirect evidence. Capture an authenticated screen with the session browser and import it instead. workflow review <spec.json> --workspace <directory> --key <key> prepares an image-grounded review; it does not validate runtime behavior or trigger repairs. workflow export <operation-id> --workspace <directory> --destination <new-directory> materializes completed outputs without inference or overwriting differing files. Register HTML plus all its assets with logical relativePath mappings, or use the SDK's collectBundleFiles on an isolated generated-output directory, so references survive custody and export. This does not package an existing project from receipts.

12ui workflow layerdoc <operation-id> --workspace <directory> reads a completed native conversion without a hosted request. The SDK exposes loadWorkflowLayerDoc({workspace, operationId}) and loadLayerDocBundle({directory}) for a relocated export. Both return canonical document, absolute document/manifest paths and an assets map from artifact ID to verified local path, relative path, SHA-256 and media type; raster dimensions are checked against the document.

Native registration requires document.layerdoc.json, layerdoc-assets.json and mapped raster files. The canonical document has role layerdoc; the sidecar has role layerdoc-assets and schema 12ui.layerdoc-assets.v1, with assets: {artifactId: {path, sha256, mediaType}}. Every file needs its portable relativePath; referenced rasters use role asset. This local reader does not provide an offline editor. Standard hosted 12ui convert <layerdoc.json> does not read the sidecar: it requires hydrated HTTP asset references. Uploading and hydrating local assets remains a separate API integration.

Design Corpus inspiration

TwelveUiCorpusClient supports public status, inspiration and logo searches, reference metadata, and image downloads without a 12ui account or credits. Retrieval is free for authenticated callers too; abuse and service-budget limits still apply. Supplied credentials retain the design.corpus.retrieve scope and are never silently discarded after an authentication failure.

import { TwelveUiCorpusClient } from '@12ui/design';

const corpus = new TwelveUiCorpusClient({
  origin: process.env.TWELVE_UI_ORIGIN ?? 'https://12ui.com',
});

const status = await corpus.status();
const inspiration = await corpus.inspire({
  q: 'Editorial architecture home page with warm materiality and asymmetric typography',
  mode: 'balanced',
  k: 4,
}, {
  idempotencyKey: 'example-home-v1',
});

const first = inspiration.items[0]!;
const metadata = await corpus.reference(first.id);
const image = await corpus.download(first.id, 'ref-hd');

Every inspiration request requires a stable idempotency key. See docs/corpus-v1.openapi.yaml. download accepts thumb, thumb-hd, ref, and ref-hd; the original thumb/ref sizes remain supported.

For agent workflows that need four reference images, the CLI calls /api/v1/corpus/inspire, downloads the full reference images in parallel, verifies each WebP, and writes a content-hashed manifest:

node "$TWELVE_UI_REPO/packages/12ui/dist/cli.js" corpus inspire \
  --query "Editorial architecture home page with warm materiality and asymmetric type" \
  --count 4 \
  --idempotency-key design-run:home-v1 \
  --out-dir ./references

balanced is the standalone CLI, SDK and MCP default, with or without credentials. direct stays close to the literal query, balanced weighs relevance, quality, and variety evenly, and adventurer follows the query's most distinctive directions toward less expected references. The modes are locked server-side; callers cannot tune their internal ranking weights. Anonymous requests accept up to 24 references and an 8 KB query. Explicit hedge requires an account for hosted planning; it remains free to the customer but incurs service model costs. For account-free planning, develop directions locally and retrieve them through balanced, direct or adventurer.

For a redesign, add --reference-image <png|jpeg|webp>. The CLI hashes the private source into stable idempotency and local evidence, while Design Corpus uses one aggregated image-and-text embedding to retrieve visually relevant directions. The source bytes are forwarded ephemerally and are not persisted by 12ui.

The output directory must not already exist. Before dispatch, the CLI writes inspire-attempt.json with the exact request and stable idempotency key. A successful run also contains manifest.json, inspire-evidence.json with the exact upstream response, four numbered reference files, and a durable digest receipt for each image under .reference-receipts/. If the HTTP result is ambiguous or one or more image downloads fail, finish the same allocation while preserving its retrieval identity:

node "$TWELVE_UI_REPO/packages/12ui/dist/cli.js" corpus resume \
  --out-dir ./references \
  --origin https://12ui.com

corpus resume reuses the attempt's idempotency key. The Worker either returns the original stored response or reports the still-pending request; it never dispatches a second embedding for that identity. Reusing a key with a different validated request returns 409 idempotency_conflict. A reference already on disk is accepted only when its bytes match its exclusive digest receipt.

The three account-free modes are direct, balanced and adventurer; hedge is an explicit account-only mode. Public requests do not accept random seeds, browse grouping IDs, free-form ranking weights or corpus filters. HTTP 429 responses include Retry-After guidance: wait, then resume the same attempt instead of starting sign-in or buying credits. 12ui corpus status reads the release contract without starting retrieval.

Multi-page packages

TwelveUiConversionPackageClient accepts the version-1 package manifest plus explicit screenshot, LayerDoc, and raster-asset parts. It polls one durable parent operation while the service converts missing viewports and exports final pages in parallel.

import { TwelveUiConversionPackageClient } from '@12ui/design';

const packages = new TwelveUiConversionPackageClient({
  origin: process.env.TWELVE_UI_ORIGIN ?? 'https://12ui.com',
  apiKey: process.env.TWELVE_UI_API_KEY!,
});

const created = await packages.createPackage({
  manifest: {
    version: 1,
    output: 'layerdoc',
    pages: [{
      id: 'home',
      ordinal: 0,
      viewports: [{ id: 'hero', ordinal: 0, screenshot_part: 'home-hero' }],
    }],
  },
  screenshots: [{
    partId: 'home-hero',
    bytes: screenshotBytes,
    mediaType: 'image/png',
  }],
});

const completed = created.status === 'succeeded'
  ? created
  : await packages.waitForPackage(created.id);
const home = await packages.downloadPage(completed, 'home');

See docs/CONVERSION_PACKAGES.md for the strict manifest, asset mapping, normalization, page-join, and limit contract.

CLI

export TWELVE_UI_API_KEY=your-key
12ui improve https://example.com --direction "Warm editorial precision" --out-dir ./improve-kit
12ui improve https://example.com --target ./approved.png --repo ./app --out-dir ./alignment-kit
12ui convert ./screen.png --output layerdoc --out-dir ./converted
12ui convert ./screen.png --output html --model pro --width 1440 --out-dir ./responsive --timeout-ms 7200000
12ui convert ./screen.layerdoc.json --output html_fixed --out-dir ./fixed --idempotency-key screen-html-v1
12ui convert ./screen.layerdoc.json --output pptx --out-dir ./slides --idempotency-key screen-pptx-v1
12ui convert <layerdoc-conversion-id> --output html_fixed,pdf,psd,pptx,sketch --out-dir ./exports
12ui convert package --manifest ./package.json --out-dir ./pages
12ui resume conversion-id

The hosted 12ui improve CLI composes local Playwright capture, the existing draft and convert commands, and a local selector-anchored planning stage. It accepts a URL or source screenshot, records each stage in improve.json, and replays settled work. --target skips generation and aligns a supplied design image or LayerDoc to the captured URL; --dry-run prints catalog price ceilings without network access. The kit ends at responsive target artifacts and an annotated implementation plan; it never applies code.

convert package submits the ordered viewports of one continuous page as ONE package conversion per page, which is what preserves page order and stitching; converting a continuous page one image at a time loses both. branch execute uses that shape only for declared web_page documents; complete app states are separate one-viewport pages. Every viewport of a page must share one width, checked locally before anything is bought. A viewport may name sourceConversionId to reuse an already succeeded conversion of exactly those bytes instead of paying for it twice.

Draft dispatch and every branch network request stay in the foreground. Draft returns after its slots are durably dispatched; 12ui next <run-dir> --wait repairs recorded never-started slots, polls, and downloads. Branch execute and resume remain foreground until terminal. A second shell can run 12ui next <run-dir> for per-item state without dispatching replacement work. Do not infer progress from a directory listing.

An HTML branch can become a clickable prototype in either of two equivalent ways: pass --prototype to branch execute, or run 12ui prototype <run-dir> afterward. The post-export stage splits application states, canonicalizes the shared shell, derives navigation from branch.plan.json, preserves real content, and creates holding pages when the plan names a route that was not exported. Standalone 12ui prototype <run-dir> defaults to --labels none, using deterministic links, forms and plan edges without a 12ui account. Explicitly authorized --labels 12ui adds one hosted interaction-label call per exported screen using the strict navigate | dropdown | modal | none schema.

12ui prototype <run-dir> --labels workflow --workspace <directory> inventories the local HTML and prepares stable per-screen label operations, returning awaiting_labels without inference or hosted authentication. Execute the returned prepared IDs through workflow execute, register real outputs with the exact attempt number, then repeat the same prototype command. Dispatched/reconciling IDs need recovery, not execution. Completed results are checked against the exact DOM candidates, known destinations and source HTML/plan/completion before build. Generic image workflow labels annotations cannot be substituted. Duplicate IDs, unknown destinations and contradictory action fields are rejected before immutable workflow success. Native local pages permit only navigation to real pages or none. 12ui branch resume refuses to replace this pause with hosted labeling.

The manifest preserves source custody, operation IDs and actual provider/funding/ usage facts. labels.costMicros counts new hosted prototype-label calls only; workflow model execution still consumes the chosen plan/API budget. Unchanged source/candidate content reuses operation IDs, including after branch/workspace relocation. Linked remote assets are not part of this source snapshot.

The output replaces <run-dir>/branch/prototype/ only after exported HTML, a complete or explicitly accepted partial plan, semantic viewport ids, and the hard runtime gates pass. Load/console failures, duplicate ids, broken targets or interactions, malformed holding composition, inconsistent canonical shells, incorrect linked active navigation, and broken deep-link history still refuse publication. Incomplete dropdowns are never given invented options: they become static controls, while dropdown, zero-action-page, and majority-holding defects publish as explicit degradations in prototype.status.json, the run journal, and proto-manifest.json. Any holding page, skipped shell transplant, shell size residual, or untested script direction also remains a visible warning and measured manifest fact. Prototype polish is opt-in for its first release: use --prototype --polish on branch execution or 12ui prototype <run-dir> --polish. The manifest, polish report, and run journal retain per-rule fired, silent, and reverted counts, and runtime verification reads the polished page copies.

Playwright's Chromium registry lives at cache/ms-playwright inside the same XDG, HOME, or session data root selected for the managed CLI. If Chromium is absent, prototype stops before labeling and prints the exact version-matched install command; it never starts a browser download on its own.

Each conversion also writes a verified <out>.assets/manifest.json plus every signed raster artifact beside the requested result. Set TWELVE_UI_ORIGIN to override https://12ui.com; waits default to the operation expiry and can be bounded explicitly with --timeout-ms.

convert blocks and records the original filenames before admission. If its shell is interrupted after a conversion ID is returned, bare resume restores every artifact in that original purchase. --out-dir keeps the recorded basenames but moves recovery into another directory. For an older or externally created operation without a local recovery record, the power form names its exact output and destination:

12ui resume conversion-id --output layerdoc --out ./screen.layerdoc.json

If admission fails before emitting an operation ID, repeat the exact request with the same explicit --idempotency-key so the service can replay the original operation without repeating settled paid work. When the key is omitted, the client generates a new UUID.

Image conversions accept --model fast|standard|pro; omission selects standard. Beginning with layerdoc-worker-v148 and still in the current layerdoc-worker-v194, Fast, Standard, and Pro all use gpt-5.6-terra-low for primary extraction. Fast retains color-guided deterministic inpainting, source-grounded flat-border cutouts, and 1x source crops without secondary metadata refinement, generative cleanup, provider background removal, or upscaling. Standard has no secondary metadata refinement and uses one target-scoped atomic GPT Image 2.5 Flare result for each opaque clean target, with Pixelcut-first alpha isolation and Bria admitted only after a durable hard-invalid or reconciled terminal Pixelcut failure. Standard performs no Luna candidate review. Pro retains a separate gpt-5.6-terra-low metadata-refinement call, a target-scoped atomic clean plus the shared whole-image clean for atomic-region targets, one comparative Luna review, and the complete revision-frozen FAL alpha portfolio. The clean-stage request requires opaque output. Provider-routed cutouts keep enhanced upscaling; accepted deterministic Fast cutouts are resized locally. The option is not accepted for LayerDoc input because downstream compilation is deterministic.

Use --width <px> to set the native output canvas width. The CLI resizes image input proportionally before upload, upscaling or downscaling as needed. The selected model may analyze a smaller internal raster without changing that authored width; do not switch to Pro merely because the native canvas exceeds Standard's analysis edge. For example, an 800x600 source with --width 1000 becomes a 1000x750 conversion canvas, and a 1536x1024 Standard source remains a 1536x1024 native canvas while analysis is bounded to 1500x1000. --width 390 turns a 1170 px-wide 3x phone capture into a 390 px conversion canvas. The option is not accepted for LayerDoc input or resume.

LayerDoc input accepts the public v2 JSON downloaded from the API. Its signed raster references must still be valid and must belong to the same authenticated account. The service resolves those owned artifacts directly; it does not fetch arbitrary remote URLs. LayerDoc input produces layerdoc, html, html_fixed, svg, png, jpg (JPEG), webp, pdf, psd, pptx, or sketch. The typed Node client and MCP integration documented below retain the exact-profile web_project and app_project integration surface.

Review stored work

12ui review ./my-run
12ui review --all

review starts a read-only-by-default server on an ephemeral localhost port, prints its URL, and opens it in the browser. The page places draft candidates side by side, shows branch screens, exported page HTML, and a branch prototype, and renders conversion outputs. Pass one run or workspace directory, or use --all to find automatic draft workspaces in the current system temp directory and runs under the current project's .12ui directory. The server never binds to a network interface.

This discovery follows the CLI's existing storage contracts: automatic drafts live under the system temp root as 12ui-* directories with draft.json and candidates/ (src/draft-workspace.ts); branch artifacts live under <run-dir>/branch/{screens,pages,prototype} (src/branch-run-record.ts); workspace commands append artifacts to <workspace>/journal.jsonl (src/run-journal.ts), and conversions write outputs beside their input unless --out-dir selects a workspace (src/cli-convert-command.ts). An explicit directory is searched for those markers so a parent containing several stored runs can be reviewed at once.

Notes and marks are the only automatic writes. Each run stores them atomically in <run-dir>/review.json, mode 0600, and reloads them whenever the page is opened. pick and approve are deliberately separate marks; Clear records no mark. Agents can consume the file directly:

{
  "version": 1,
  "updatedAt": "2026-08-21T01:23:45.000Z",
  "items": {
    "draft-candidate-a-0123abcd": {
      "feedback": {
        "note": "Keep the hierarchy and reduce the footer.",
        "mark": "pick",
        "updatedAt": "2026-08-21T01:23:45.000Z"
      },
      "edits": [
        {
          "id": "edit-0123abcd",
          "prompt": "Change the heading to Northstar notes.",
          "createdAt": "2026-08-21T01:25:00.000Z",
          "editOperationId": "edit-operation-id",
          "renderOperationId": "render-operation-id",
          "original": "screen.layerdoc.json",
          "layerdoc": "review/edits/edit-0123abcd.layerdoc.json",
          "html": "review/edits/edit-0123abcd.html"
        }
      ]
    }
  }
}

Item keys are stable hashes of their kind and run-relative path. mark is "pick", "approve", or null; edits is omitted until an edit succeeds.

When an item is a LayerDoc and conversion credentials are configured, the page offers an explicit text edit. It shows the price first and asks for confirmation before calling the existing POST /api/v1/edit contract. A Design edit is a metered action: it uses the weekly allowance when available or costs $0.03; requested image actions may cost another $0.02-$0.30. The review server never applies an edit by itself. A successful edit and its deterministic fixed HTML render are written under <run-dir>/review/edits/ and displayed beside the original.

Every completed HTML branch has an explicit Prototype action; opening review never starts it. Holding pages expose Fill this gap only when credentials are configured. Its button states $0.48+ before confirmation: $0.03 for one Standard preserve-structure image claim, $0.45 for Standard HTML conversion, plus the cheap label calls made when the prototype is rebuilt. The new page and plan live in a private prototype source overlay, so original branch evidence is not rewritten, and a durable receipt records the claim, conversion, and artifacts.

The run journal

Every command that owns a workspace directory — a draft run directory, a branch out-dir, or a convert output directory — appends what it did to <workspace>/journal.jsonl. One JSON line when the command begins and one when it exits, including refusals and failures. Draft and branch network work stays in that foreground process, so a run's whole history remains in one place.

Each line carries the canonical command name, a digest of the argv (hashed with credential values redacted, never written down), the run and idempotency identities, whether the command can spend money, the outcome and a normalized error class, the artifacts it produced, the ids it bought, whether the run is terminal, whether the work detached, and the process id. 12ui capabilities reports the field list; the file is append-only and never rewritten, so a reader tolerates a torn final line while a writer is mid-append.

The journal exists because one command can span several service stages, and a second shell needs durable evidence rather than inference from a directory.

LayerDoc to downstream formats

The raw LayerDoc representation can be submitted directly to a second conversion. This makes it possible to edit the document's text, geometry, or style before compiling responsive HTML or a fixed export while retaining its signed asset refs:

import fs from 'node:fs';
import { TwelveUiConversionClient } from '@12ui/design';

const client = new TwelveUiConversionClient({
  origin: process.env.TWELVE_UI_ORIGIN ?? 'https://12ui.com',
  apiKey: process.env.TWELVE_UI_API_KEY!,
});

const created = await client.createConversion({
  layerdoc: new Uint8Array(await fs.promises.readFile('./screen.layerdoc.json')),
  output: 'html',
});

const completed = created.status === 'succeeded'
  ? created
  : await client.waitForConversion(created.id, { expiresAt: created.expires_at });
const html = await client.downloadResult(completed.id, 'html');
await fs.promises.writeFile('./screen.html', html.bytes);

For generated responsive layouts, derive from the successful image-to-LayerDoc operation instead of uploading the image again:

const responsive = await client.createConversion({
  sourceConversionId: imageToLayerDoc.id,
  output: 'html',
  responsiveQuality: 'pro', // standard | pro
});

This authenticated path reuses the canonical LayerDoc and raster assets from imageToLayerDoc, consumes export quota, and starts directly at responsive reference generation. The source conversion must still be retained and must have been produced by the current pipeline revision.

While the operation is queued or running, poll it normally and read responsive_preview. Its frames are returned in mobile, tablet, then compact desktop plan order. Each frame moves through waiting, generating, generated, extracting, binding, and complete; its signed artifact appears immediately after the real generated reference PNG is durably registered. completed and total count reference, extraction, and binding as three durable steps per admitted anchor, while progress.percent remains the overall conversion progress for a single progress bar.

Project output uses the same client method and returns a deterministic ZIP:

const createdProject = await client.createConversion({
  layerdoc: new Uint8Array(await fs.promises.readFile('./screen.layerdoc.json')),
  output: 'web_project',
  profile: {
    version: 1,
    framework: 'react',
    styling: 'tailwind',
    language: 'typescript',
    packaging: 'project',
  },
});

const projectOperation = createdProject.status === 'succeeded'
  ? createdProject
  : await client.waitForConversion(createdProject.id, {
      expiresAt: createdProject.expires_at,
    });
const project = await client.downloadResult(projectOperation.id, 'web_project');
await fs.promises.writeFile('./screen-react.zip', project.bytes);

The complete version-1 capability matrix is documented in docs/EXPORT_FORMATS.md. Unsupported framework, styling, language, or packaging combinations fail before upload; the client does not substitute a nearby target.

The 10 web framework slugs are html, react, next, vue, nuxt, svelte, sveltekit, angular, astro, and lit. The 9 app framework slugs are expo, react_native, flutter, ionic_capacitor, swiftui, uikit, jetpack_compose, android_views, and compose_multiplatform. Import WEB_PROJECT_CAPABILITIES and APP_PROJECT_CAPABILITIES from this package to enumerate the exact styling, language, and packaging cross-products at runtime. For web output, component is reusable component source, page is a route/page entrypoint, and project is a runnable scaffold. For app output, screen is integration-ready screen source for an existing app, while project adds the runnable scaffold and build configuration.

Hosted /convert two-phase workflow

The Node client above remains API-key authenticated and may request any valid image output directly. The free hosted web page uses the same HTTP resources with an intentionally narrower contract:

  1. Create one image conversion with output: "layerdoc".
  2. Poll the operation and replace the interactive preview only when operation.preview.revision increases.
  3. Fetch the final LayerDoc representation after the source succeeds.
  4. Keep that hydrated JSON in memory and create independent LayerDoc-input jobs for html, svg, png, jpg, webp, pdf, psd, pptx, sketch, web_project, and app_project. Different formats and project profiles can run in parallel; a repeated completed format should download the cached representation rather than create another run.

No special export endpoint is involved. The source conversion remains the web session root, and each export is an ordinary POST /api/v1/convert followed by polling GET /api/v1/convert/:id. LayerDoc input is accepted only after its source run has succeeded because the Worker verifies its signed artifacts, expiry, and ownership before importing them.

Anonymous hosted-page requests send X-12UI-Public-Preview: 1 and the same browser-generated X-12UI-Public-Visitor value. Public image creation also includes cf-turnstile-response in multipart form data; its verified action is 12ui_convert_image. Public quotas are 5 Fast, 2 Standard, no Pro, and 20 exports per salted IP hash per UTC week (Monday 00:00 UTC to the next Monday). Signed-in and API accounts receive 50 Fast, 20 Standard, 2 Pro, and 200 exports per stable account id and UTC week. GET /api/v1/convert/quota returns all buckets; successful POST responses identify the admitted bucket and return its limit and remaining count. Weekly exhaustion returns 429 with Retry-After and X-RateLimit-Reset at the next Monday 00:00 UTC.

All runs are sponsored and do not check or debit Login credits. Provider, model, request-id, reservation, actual-cost, principal-tier, and account-id records are retained in durable ledgers independent of expiring conversion artifacts. Public headers are for the trusted anonymous preview; CLI and MCP consumers should keep using a Login-issued API key.

Running LayerDoc operations may include an immutable preview: structure contains the final layer tree and prepared source, while standard adds 1× crops and cleaned plates. result remains reserved for the final enhanced, manifest-last publication. progress.active reports durable completed/total counts for each materialization lane.

Progressive Node consumer

waitForConversion intentionally returns only the terminal operation. A consumer that wants live progress or previews should poll getConversion and apply every operation snapshot:

import fs from 'node:fs';
import { TwelveUiConversionClient } from '@12ui/design';

declare function renderLayerDoc(document: unknown): void;

const client = new TwelveUiConversionClient({
  origin: process.env.TWELVE_UI_ORIGIN ?? 'https://12ui.com',
  apiKey: process.env.TWELVE_UI_API_KEY!,
});

const created = await client.createConversion({
  bytes: new Uint8Array(await fs.promises.readFile('./screen.png')),
  mediaType: 'image/png',
  output: 'layerdoc',
  model: 'standard',
});
// The upload carries the image's pixels and colour profile only, named
// `source.png`: no filename, camera, author or location leaves the machine.

let operation = created;
let displayedRevision = 0;

while (operation.status === 'queued' || operation.status === 'running') {
  const progress = operation.progress;
  if (progress) {
    console.log(progress.percent, progress.stage, progress.milestone);
    for (const lane of progress.active ?? []) {
      console.log(lane.kind, lane.completed, lane.total, lane.status);
    }
  }

  if (operation.preview && operation.preview.revision > displayedRevision) {
    displayedRevision = operation.preview.revision;
    renderLayerDoc(operation.preview.document);
    // operation.preview.artifacts contain signed hrefs that are usable now.
  }

  await new Promise((resolve) => setTimeout(resolve, 1_000));
  operation = await client.getConversion(operation.id);
}

if (operation.status !== 'succeeded' || operation.result?.kind !== 'layerdoc') {
  throw new Error(operation.error?.detail ?? `Conversion ${operation.status}`);
}

// The terminal result is authoritative and replaces any displayed preview.
renderLayerDoc(operation.result.document);

Raw HTTP consumers should use Accept: application/json while polling and respect the response's Retry-After header (currently one second). Prefer: wait=20 only allows the create request to wait for an early result; it is not a streaming connection. There is no SSE or WebSocket contract.

Progress and preview rules:

  • progress.percent is the weighted server calculation; do not derive a percentage from the stage name.
  • progress.active is optional and image-specific. Do not assume every lane is present or that lane order is fixed.
  • milestone is structure_ready or standard_ready once that preview is available.
  • Previews currently apply to output=layerdoc. Downstream HTML and fixed export operations still expose progress, but publish only their terminal result.
  • Preview revision 1 is quality: "structure"; revision 2 is quality: "standard". Treat revisions as immutable snapshots.
  • A preview artifact id is never repointed to different bytes. Signed href values expire with the operation; re-read the operation to refresh URLs.
  • On succeeded, use result as authoritative. On failed or expired, use error and discard any displayed preview as a non-terminal aid.

MCP

12ui mcp

The server exposes the same durable operations used by the CLI and SDK:

  • design.workflow.prepare, execute, register, continue, fail, status, import, capabilities, capture, export and layerdoc use the persistent local service. Preparation accepts either a generic request or a recipe/input pair. Local operations do not trigger 12ui onboarding; paid execution needs explicit policy. Session registration and failure include the returned attemptNumber.
  • design.convert creates a conversion, waits for it, and materializes the result and verified artifact manifest. Pass imagePath for PNG/JPEG/WebP or layerdocPath for public LayerDoc v2 JSON. Pass the exact profile for web_project or app_project.
  • design.convert.status reads an existing conversion's durable progress, previews, terminal result, or error without creating or retrying work.
  • design.corpus.status reads corpus release/idempotency capability without authentication or running retrieval.
  • design.corpus.inspire runs free corpus retrieval and materializes its attempt evidence, manifest, and images in a new outDir. Balanced is the default; anonymous requests accept up to 24 references. Explicit hedge requires an account. design.corpus.resume continues an incomplete attempt with its recorded key. These tools never trigger automatic onboarding.
  • design.draft.status and design.branch.status read durable workflow state. Branch status attempts a live refresh by default, then falls back to the local snapshot if the service is unavailable.

The server also starts without 12ui credentials: the local workflow tools, the corpus tools and the design workspace tools below that only read and record work need none, and the hosted tools ask to sign in when called.

The Design workspace (ui://12ui/slate.html) grows from one finished draft run into rounds of options, edits with lineage, inspiration, and a selection of any version. Nothing in it costs money and nothing in it shows a price: it draws with your own Codex on this Mac (your ChatGPT plan, never an API key) and searches the free reference corpus. Twelve tools:

  • design.slate.show renders the workspace in hosts that render an interactive card, such as Codex desktop, and returns the options, versions, file paths and the continuation command as text elsewhere. design.slate.data returns the same facts without a card, so an agent can confirm a selection or a hand-off (pick.versionId, pick.sha256, and the file at pick.imagePath, a durable copy that survives the OS sweeping the temp folder; pick.imagePath is null, with pick.fileState missing or changed and pick.intact false, when that copy is gone or no longer matches, and no file that is not there is ever named); design.slate.open is the sidebar entry for the most recent active workspace. These three are model-visible and never start work. show and open are titled "Design workspace".
  • App-only tools, which the host hides from the model: design.slate.image and design.slate.reference (pictures for the card, the second from the free corpus and cached in the workspace), design.slate.inspire (a free balanced-mode reference search, at most 24 results, no account; an identical search is answered from the record) and design.slate.inspiration (the selected references, at most eight, that condition the next Design round), design.slate.pick (Select, with an optional reason, and a durable copy of the image), design.slate.handoff (records a Branch or Convert request) and design.slate.status (a free read of the workspace, its runners' liveness, and whether this Mac can draw images).
  • design.slate.run and design.slate.resume are the only tools that start work, and only from a click in the screen. Design (new options, or more like the shown version) and Edit (an instruction plus an optional scribble, sent as the version and an annotated copy of it) write an approval record outside the run directory, spawn a detached 12ui slate-runner process, and return at once. The runner owns the work to a terminal state, so it does not depend on how long the host keeps this server alive: it runs codex exec's native image call, one call per option, in your own Codex home (your CODEX_HOME, else Codex's default ~/.codex), so each draw's session lands beside your others. It ignores your Codex config except service_tier, so a Fast lane you chose also speeds draws. The model that runs the call only wraps the image tool: it is gpt-6-luna at low effort when your Codex model cache lists it with low reasoning (about 8-10 s faster per option), else gpt-6-astra at medium; TWELVE_UI_CODEX_MODEL names another. The reference images reach it as short copies under /tmp that are removed when the call ends. Every call has a stable id (slate-<opId>-<slot>), so Resume replays the same work and never draws a finished option twice. When Codex is not ready on this Mac (no CLI, no ChatGPT login, no image model) the dialogs say why and stay disabled; the workspace never buys an alternative. Set TWELVE_UI_CODEX_BIN to choose the Codex executable.

A hand-off records the request durably (Branch: your words, verbatim; Convert: the format and its options) with a verified copy of the image, and sends the agent a short message. The agent reads the record with design.slate.data and runs the filled-in 12ui command it names (12ui branch execute for a Branch, 12ui convert for a Convert). 12ui slate-runner is an internal command and is not a public surface.

Without the MCP tools: the workspace as a web page. 12ui workspace open --concept "<brief>" starts a workspace from a brief (or 12ui workspace open [<run-dir>] [--latest] opens a finished draft run's), the route wherever the workspace does not show in the conversation ([--wait] [--port <n>] [--no-open] apply to both). It serves the same workspace (the same screen, built with target browser) on 127.0.0.1 only, behind a random token in the address it prints as one JSON line ({"workspace":"ready","url":...}), and opens the system browser unless --no-open (BROWSER names another program). A small host shim in the page stands in for the MCP Apps host: the screen's tool calls go to the same handlers 12ui mcp uses, confined to that one run, and Design and Edit run on this Mac through the same detached runner and local Codex, with no agent needed to generate. With --wait the command blocks until the user Selects, or sends a Branch or Convert request, then prints one JSON line (decision, runDir, pick, handoff, messages, text and view, the facts design.slate.data returns) and exits 0; without it, it serves until interrupted and prints one such line per decision. The 12ui-design skill starts a workspace this way wherever the hosted screen does not show. Under codex exec's sandbox, read-only and workspace-write refuse the server's port (listen EPERM: operation not permitted 127.0.0.1); workspace-write with network access (-c sandbox_workspace_write.network_access=true) and the 12ui state folder added (--add-dir ~/.local/share/12ui, which the workspace writes to) runs everything, Design and Edit included; full access needs none of it.

Among these tools, only design.convert creates metered work; corpus retrieval, including the workspace's own search, is free and subject to abuse limits. design.workflow.execute can use a funded provider only with its explicit authorization policy. Set an idempotencyKey for any ambiguous conversion create that may need to be repeated; otherwise the conversion client generates a new UUID. Corpus retrieval always persists its key before the request.

Draft and Branch execute/resume remain deliberate CLI workflows (12ui draft and 12ui branch). They coordinate hosted service runs, durable local run directories, progress streaming, and multi-page packaging; the MCP surface does not duplicate those orchestrators or quietly dispatch paid work from a status call.