Skip to content

jdmnk/styles-iterator

Repository files navigation

🎨 styles-iterator

Generate, run, and visually compare AI-generated interface variants in isolated Git worktrees.

demo.mp4


styles-iterator is for frontend developers and product teams using Claude Code, Codex, or Cursor Agent who want to explore several visual directions at once and compare and iterate on them easily.

styles-iterator run --count 3 --concurrency 3 "Make the app feel more premium, modern, and conversion-focused"

The quoted prompt is the shared goal applied to every variant. Each variant still gets a distinct style direction from the prompt.variants presets in your config (e.g. Minimal Swiss SaaS, Neo-brutalist chaos, Dark elegant), so the three windows above explore that goal three different ways. --count walks the preset list (wrapping if it runs out); --concurrency is how many generate in parallel. To explore one style instead, give prompt.variants a single entry or run with --count 1.

Example CLI surface:

styles-iterator

Generate multiple UI variants in isolated git worktrees, run them on separate ports, and compare them visually in a local browser harness.

Usage:
  styles-iterator init [--format ts|mjs] [--force]
  styles-iterator doctor [--config <path>]
  styles-iterator run [prompt] [--agent cursor|codex|claude] [--count 3] [--concurrency 3] [--model <model>] [--no-open] [--no-serve]
  styles-iterator serve [session-id] [--config <path>] [--no-open]
  styles-iterator list [--session <id>]
  styles-iterator diff <variant-id> [--session <id>]
  styles-iterator accept <variant-id> [--strategy cherry-pick|squash|apply] [--session <id>] [--cleanup]
  styles-iterator cleanup [session-id] [--all] [--delete-branches] [--purge]

What It Does

The CLI will:

  1. require a clean base Git worktree by default, except for the loaded styles-iterator.config.*
  2. create one branch and Git worktree per variant under .styles-iterator/worktrees/
  3. run the configured agent against each worktree: Claude Code CLI with the cheap haiku model by default, Codex CLI with gpt-5.4 low when agent: "codex", or Cursor Agent when agent: "cursor"
  4. run configured checks such as lint and typecheck
  5. commit each successful variant on its own branch
  6. run each variant on its own local port
  7. open a local harness with baseline and variants side by side
  8. let you accept a winner with cherry-pick, squash, or patch application

Install From Source

pnpm install --frozen-lockfile
pnpm build
pnpm link --global

Then verify the linked CLI:

styles-iterator --help
styles-iterator --version

To run without linking:

node dist/cli.js --help

Status

This repository is ready for source installs. The npm package is not published yet, so do not use npm install -g styles-iterator until a release has been published and verified.

Requirements:

  • Node.js 20.11 or newer
  • pnpm 10
  • Git
  • Claude Code CLI available as claude (default), Codex CLI available as codex when agent: "codex", or Cursor Agent CLI available as agent when agent: "cursor"

Install Cursor Agent CLI

Cursor Agent is optional and only needed when agent: "cursor". It is a separate tool from this package and is not installed by pnpm install. Install and authenticate it by following Cursor's official CLI documentation. After setup, make sure the agent command is on your PATH and signed in (agent status).

Notes:

  • If your install only exposes the legacy cursor-agent command, set cursor.bin: "cursor-agent" in styles-iterator.config.*.
  • For CI or other non-interactive environments, use a Cursor API key instead of browser login: export CURSOR_API_KEY="your_api_key_here".
  • The cursor shell command (the desktop app launcher) is a different tool — styles-iterator needs the Cursor Agent CLI.

Install Codex CLI

Codex CLI is an optional generator, used when agent: "codex". Install and authenticate it by following OpenAI's official Codex CLI documentation.

For non-interactive styles-iterator run usage, complete the interactive codex sign-in first or configure API-key auth in your Codex environment.

Enable Codex in project config:

export default {
  agent: "codex",
  codex: {
    model: "gpt-5.4",
    reasoningEffort: "low",
  },
};

Install Claude Code CLI

Claude Code CLI is the default generator. Install and authenticate it by following Anthropic's official Claude Code documentation. Running claude once walks you through interactive sign-in.

For CI or other non-interactive environments, set an API key instead of the interactive login: export ANTHROPIC_API_KEY="your_api_key_here".

Enable Claude in project config (it is the default, so this is only needed when another agent is configured):

export default {
  agent: "claude",
  claude: {
    model: "haiku",
  },
};

Initialize Config

styles-iterator init

This writes styles-iterator.config.ts. The generated TypeScript config includes a local config type, so editor type-checking works even when styles-iterator is installed globally or linked from source instead of added to the target repo's dependencies. You can edit this config without committing it before every run. The clean-worktree check ignores the loaded config file, while other uncommitted app changes still block run and accept unless you pass --allow-dirty. Commands search for config from the current directory upward to the Git root. If a config lives in a subdirectory, agent, prepare, check, and dev-server commands run from that config directory inside each generated worktree.

For plain Node environments that cannot import TypeScript config files directly, use:

styles-iterator init --format mjs

Example Config

export default {
  count: 3,
  concurrency: 3,
  basePort: 47000,
  includeBaseline: true,
  agent: "claude",

  cursor: {
    bin: "agent",
    model: "Composer 2.5",
    outputFormat: "stream-json",
    timeoutMs: 10 * 60_000,
  },

  codex: {
    bin: "codex",
    model: "gpt-5.4",
    reasoningEffort: "low",
    sandbox: "workspace-write",
    approvalPolicy: "never",
    timeoutMs: 10 * 60_000,
  },

  claude: {
    bin: "claude",
    model: "haiku",
    outputFormat: "text",
    permissionMode: "acceptEdits",
    timeoutMs: 10 * 60_000,
  },

  app: {
    prepareCommand: "pnpm install --frozen-lockfile",
    devCommand: "pnpm dev --port {port}",
    url: "http://127.0.0.1:{port}",
    healthPath: "/",
  },

  checks: {
    commands: ["pnpm lint", "pnpm typecheck"],
    allowFailure: true,
  },

  routes: ["/", "/pricing", "/dashboard"],
};

Commands

styles-iterator init [--format ts|mjs] [--force]
styles-iterator doctor [--config <path>]
styles-iterator run [prompt] [--agent cursor|codex|claude] [--count 3] [--concurrency 3] [--model <model>] [--no-open] [--no-serve]
styles-iterator serve [session-id] [--config <path>] [--no-open]
styles-iterator list [--session <id>]
styles-iterator diff <variant-id> [--session <id>]
styles-iterator accept <variant-id> [--strategy cherry-pick|squash|apply] [--session <id>] [--cleanup]
styles-iterator cleanup [session-id] [--all] [--delete-branches] [--purge]

What Happens During Run

After styles-iterator run, the CLI creates a session under .styles-iterator/sessions/{sessionId} and one Git worktree per variant under .styles-iterator/worktrees/{sessionId}.

While a variant is generating, the selected agent is producing changes inside that variant worktree. The terminal prints changed-file summaries as the worktree changes, and raw agent output is written per variant to .styles-iterator/sessions/{sessionId}/logs/{variantId}.{claude,codex,cursor}.log. Concurrent process prefixes are color-coded in terminals that support ANSI color. Set NO_COLOR=1 to disable color or FORCE_COLOR=1 to force it.

When generation finishes, styles-iterator guards the changed files, runs configured checks, commits each successful variant on its generated branch, starts one dev server per ready variant plus the baseline, and opens the comparison harness.

If generation succeeded but starting dev servers failed, fix app.devCommand in your config and run styles-iterator serve --session <session-id>. serve reuses the existing generated worktrees and commits, starts only the dev servers plus harness, and does not run generation again. It prints the harness URL immediately, then logs each dev server command, cwd, log file, PID, and final preview URL as servers become ready. Omitting --session resumes the latest session; resume is an alias for serve.

Cursor Agent CLI Configuration

When agent: "cursor", the default Cursor command is equivalent to:

agent -p --trust --model "Composer 2.5" --output-format stream-json "<prompt>"

--trust is included because styles-iterator runs Cursor Agent in freshly-created Git worktrees. Without it, Cursor Agent may stop on each variant and ask whether that worktree directory is trusted. This does not enable --yolo/--force.

Older Cursor Agent installs may only expose cursor-agent. To use that compatibility command:

export default {
  cursor: {
    bin: "cursor-agent",
  },
};

If your installed Cursor Agent CLI uses a different command shape, configure it explicitly:

export default {
  cursor: {
    command:
      "agent -p --trust --model {model} --output-format {outputFormat} {prompt}",
    model: "Composer 2.5",
  },
};

Values inserted into cursor.command are shell-quoted automatically, so multiline prompts and model names with spaces are safe in the template form above. If you override cursor.args or cursor.command, keep --trust unless you want to approve each generated worktree interactively. Cursor Agent launches are staggered by 1.5 seconds by default to avoid races in Cursor's shared ~/.cursor/cli-config.json. Set STYLES_ITERATOR_CURSOR_LAUNCH_STAGGER_MS=0 to disable that delay, or increase it if your Cursor install still hits config-file rename errors under high concurrency.

Supported template variables include:

{prompt}
{model}
{outputFormat}
{variantId}
{variantName}
{sessionId}
{port}

Codex CLI Configuration

Enable Codex with:

export default {
  agent: "codex",
};

The default Codex command is equivalent to:

codex exec --model gpt-5.4 --config 'model_reasoning_effort="low"' --config 'approval_policy="never"' --sandbox workspace-write --color never "<prompt>"

gpt-5.4 with low reasoning is the default Codex model/effort pair because it is fast and cheaper for iterative coding. Override either value in config or on the CLI:

styles-iterator run --agent codex --model gpt-5.4 --reasoning low

The default sandbox is workspace-write, so Codex can edit the generated worktree. The default approval policy is never, because styles-iterator runs Codex non-interactively and logs output per variant. If you want Codex to ask for approvals, run Codex directly or override codex.args/codex.command for your environment.

If your installed Codex CLI uses a different command shape, configure it explicitly:

export default {
  agent: "codex",
  codex: {
    command:
      "codex exec --model {model} --config 'model_reasoning_effort=\"{reasoningEffort}\"' --config 'approval_policy=\"{approvalPolicy}\"' --sandbox {sandbox} --color never {prompt}",
  },
};

Values inserted into codex.command are shell-quoted automatically. Supported template variables include:

{prompt}
{model}
{reasoningEffort}
{sandbox}
{approvalPolicy}
{variantId}
{variantName}
{sessionId}
{port}

Claude Code CLI Configuration

Claude Code is the default agent, so no agent setting is required. Set it explicitly if another agent is configured:

export default {
  agent: "claude",
};

The default Claude command is equivalent to:

claude -p --model haiku --permission-mode acceptEdits --output-format text "<prompt>"

haiku is the default model because it is fast and cheap for iterative styling work, and the alias always resolves to the current Haiku. Pin a full id like claude-haiku-4-5-20251001 if you need a reproducible snapshot. Override it in config or on the CLI:

styles-iterator run --agent claude --model claude-sonnet-4-6 "Make the app feel more premium"

Aliases such as haiku, sonnet, and opus also work as --model values.

The default permission mode is acceptEdits, so Claude Code can edit files in the generated worktree without prompting, but it does not auto-run arbitrary shell commands. Because styles-iterator works inside throwaway git worktrees, you can switch to bypassPermissions if a project needs the agent to run commands too:

export default {
  agent: "claude",
  claude: {
    permissionMode: "bypassPermissions",
  },
};

If your installed Claude Code CLI uses a different command shape, configure it explicitly:

export default {
  agent: "claude",
  claude: {
    command:
      "claude -p --model {model} --permission-mode {permissionMode} --output-format {outputFormat} {prompt}",
  },
};

Values inserted into claude.command are shell-quoted automatically. Supported template variables include:

{prompt}
{model}
{outputFormat}
{permissionMode}
{variantId}
{variantName}
{sessionId}
{port}

App Server Configuration

Each variant gets a deterministic port:

basePort + variantIndex

By default:

v01 -> 47000
v02 -> 47001
v03 -> 47002
baseline -> 47000 + count

Configure your dev command with {port}:

export default {
  app: {
    devCommand: "pnpm dev --port {port}",
    url: "http://127.0.0.1:{port}",
    healthPath: "/",
  },
};

Visual Harness

The harness starts at http://127.0.0.1:8787 by default. It shows:

  • baseline app, when enabled
  • all successful variants
  • route selector
  • responsive viewport mode by default, plus fixed viewport presets
  • zoom control for fitting large viewports
  • a deterministic CSS-grid board with a column selector (auto/1–4)
  • per-card Focus to expand one preview to full width, Widen/Narrow column-span controls, and a drag-to-resize corner handle (free height + column-snapped width; double-click to reset)
  • close and reopen controls for preview windows
  • manual reload, plus opt-in auto reload
  • ready-only filtering
  • iframe previews
  • per-variant Reroll, which discards the current iteration and explores a fresh take on the same style direction
  • per-variant Continue…, which refines the variant from a custom prompt you type in the harness
  • + New variation, which generates an additional variant on its own worktree and port while the harness is running
  • live "working" status with a per-variant changed-file count and a rebuilding overlay on the preview while an agent runs
  • diff stat, agent summary, and agent output logs (with download links), grouped in a per-card overflow menu
  • accept button per committed variant with cherry-pick, squash, or apply

Reroll, Continue, and New variation run the agent in the background inside the live run/serve process — no need to restart serve. The harness keeps polling, so the status badge, changed-file count, and preview update as the agent works (file changes stream into the iframe through your dev server's hot reload). Each variant branch is kept as a single commit from the base commit, so accept keeps working unchanged after any number of iterations.

Iframes are fast and simple, but some apps block framing with X-Frame-Options or CSP. In those cases, use the Open link in each card.

Auto reload is disabled by default. To enable it for a project:

export default {
  harness: {
    autoRefresh: true,
    autoRefreshIntervalMs: 10_000,
    gridColumns: "auto",
  },
};

The harness UI also includes an Auto reload checkbox, so you can turn it on or off while comparing variants.

For harness UI development, run npm run smoke:harness after npm run build. It writes a standalone mocked harness HTML file and prints a file:// URL, so the harness controls can be checked without starting variant dev servers.

When accepting from the live harness, the baseline dev server is stopped before the selected variant is applied so the baseline preview cannot silently change underneath the comparison.

Example Vite/React App

A small Vite and React fixture app lives in examples/vite-react. It is meant for local smoke testing and agent prompt iteration without bringing another repository into the loop. The accompanying examples/styles-iterator.config.ts is a ready-to-run config wired to that app; the root styles-iterator.config.example.ts is the generic starter template that styles-iterator init writes into your own project.

Run the deterministic smoke test:

npm run check
npm run smoke:example

The smoke copies the example app to a temporary directory, initializes Git, runs styles-iterator run --no-serve with a fake Codex-compatible agent command, and verifies that a variant commit plus agent output log were produced. It does not install the example app dependencies or start Vite.

Accepting A Variant

styles-iterator accept v03

Default strategy is cherry-pick.

Other strategies:

styles-iterator accept v03 --strategy squash
styles-iterator accept v03 --strategy apply

Cleanup And Removal

Every styles-iterator run first stops leftover agent, check, prepare, and dev-server processes recorded by previous sessions. This protects repeated runs after crashes, terminal closes, or interrupted sessions without deleting generated worktrees or branches.

Stop servers and remove worktrees:

styles-iterator cleanup

Also delete generated branches and local session state:

styles-iterator cleanup --delete-branches --purge

Clean up every session at once (not just the most recent). Combined with --purge, this removes the entire .styles-iterator directory, including worktrees and state left behind by interrupted runs:

styles-iterator cleanup --all --delete-branches --purge

Unlink a source install:

pnpm unlink --global styles-iterator

Remove generated local state manually if needed:

rm -rf .styles-iterator

Validate This Repo

pnpm run check
pnpm run smoke:harness
pnpm run smoke:example

Before publishing a package:

npm publish --dry-run

Safety Model

styles-iterator intentionally isolates generated changes in Git worktrees, but the selected agent still runs with access to the files inside each worktree and may execute commands depending on your agent CLI permissions. Run this only in repositories and environments you trust.

The default guard rails fail variants that change:

  • package.json
  • lockfiles
  • .env*
  • migrations, database, auth, or API-looking paths
  • more than 80 files

You can relax those in config when needed.

Project Links

About

Spin up multiple AI-generated interface redesigns in parallel and compare them live in your browser.

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors