{"slug": "show-hn-airship-figma-like-visual-editor-for-claude-code-codex-and-opencode", "title": "Show HN: Airship – Figma-Like Visual Editor for Claude Code, Codex and OpenCode", "summary": "Airship Labs released Airship, a Figma-like visual editor that connects to a developer's running dev server and lets them edit code through Claude Code, Codex, or OpenCode, with no plugins or config. The CLI tool, available via npx @airshiplabs/cli, supports modes for canvas and inline editing, and claims no data leaves the machine. It works with any framework serving HTML over HTTP, including Vite, Next, Remix, and Rails.", "body_md": "**Visual editor for your codebase.**\n\nAirship puts an infinite design canvas in front of your dev server. Select an element, describe the change, and watch Claude Code, Codex or OpenCode update the source — without rebuilding your UI in a separate design tool.\n\n```\nnpx @airshiplabs/cli --target 3000\n```\n\nNo plugin. No config. Nothing added to your dependencies or your bundle.\n\n[airship.design](https://airship.design) · [CLI reference](#cli-reference) · [Configuration](#configuration) · [Questions](#questions)\n\n**1. Start your app the way you always do.**\n\n```\npnpm dev    # http://localhost:3000\n```\n\nWorks with Vite, Next, Remix, Rails, or anything that serves HTML over HTTP. No plugins required.\n\n**2. Point Airship at your dev server.**\n\n```\nnpx @airshiplabs/cli --target 3000\n```\n\nAirship connects to the port you're already running and opens the visual editor on the next\nfree port. Or install it once and use the `airship`\n\nbinary:\n\n```\nnpm i -g @airshiplabs/cli\nairship --target 3000\n```\n\n**3. Bring your coding agent.**\n\n```\nairship --target 3000 --agent codex --safe\n```\n\nPick the agent you already use and start making changes without running a separate agent interface.\n\nAirship uses the authentication you already have configured for Claude Code, Codex, or\nOpenCode. Run `airship doctor`\n\nif something does not work.\n\n`--exec`\n\nstarts your dev server and stops it again when Airship exits. Leave `--target`\n\noff and\nit reads the port from your `package.json`\n\n:\n\n```\nairship --exec \"pnpm dev\"\n```\n\nRun `airship`\n\non its own and it just asks you for the port, the agent and the mode.\n\nA CLI, and nothing else.\n\n**Nothing goes into your project.** Airship runs in front of the dev server you already have. Your build, your config and your dependencies are untouched.**Every frame is a real browser window.** A phone frame behaves like a phone, however far you zoom out. Mobile and desktop sit side by side — both live, both editable, one source file.**Changes land in your code.** Click an element and Airship knows the file and line that drew it. Describe the change, get the diff, undo it if you don't like it.**Nothing leaves your machine.** No account, no telemetry, no service to sign up for.\n\nTwo ways to look at your app. Same editor either way.\n\n** canvas** (default) — your app on a pannable canvas, one live frame per device size.\n\n** inline** — the editor on top of your own page, one window.\n\nPick one at launch with `airship --mode inline`\n\n, or switch any time from the bottom bar. Your\nchoice sticks across reloads and as you click around your app. Add `?__airship=inline`\n\nto a URL\nto try the other one once, without changing your preference; `?__airship=shell`\n\nis the way back\nto the canvas — the parameter takes the internal mode name, so it is `shell`\n\n, not `canvas`\n\n.\n\nOpen any route of your app in Airship — `/pricing`\n\n, `/settings`\n\n— and every frame opens there.\n\nOn the canvas:\n\n| Gesture | |\n|---|---|\n| wheel / two-finger | pan |\n| ⌘/ctrl-wheel, pinch | zoom at cursor |\n| space-drag, middle-drag | pan |\n| ⇧1 / ⇧2 / ⇧0 | fit / zoom to selection / 100% |\n\nClick an element and it fills the inspector. Every tab is looking at the same thing.\n\n`Edit`\n\nis position, size, spacing and layout — the shot up in [Quick start](#quick-start). `CSS`\n\nis the box model, the rules that are actually hitting the element, and your own tweaks on top:\n\n`DOM`\n\nis the tree. Click a node to select it, or drag one to move it somewhere else:\n\nPick one with `--agent`\n\n, or switch between them as you go. They are not equal, and Airship tells\nyou what you're giving up at startup.\n\n`claude` (default) |\n`codex` |\n`opencode` |\n|\n|---|---|---|---|\n| Watch it write | word by word | the whole reply at once, at the end | word by word |\n| Pick up an old chat | yes | yes | yes |\n| Branch off a chat | yes | starts fresh, and says so | yes, history kept |\n| Shows what it cost | in dollars | tokens only | in dollars |\n`--effort` |\nyes | yes | ignored |\n`--max-turns` , `--max-budget` |\nyes | ignored |\nignored |\n`--model` |\na model name | a model name | needs the `provider/model` form |\n`--safe` |\nchecks each edit and command | real sandbox |\nasks before each edit and command |\n| Install | included | included | you install it yourself |\n\nUndo is Airship's, not the agent's. It keeps the previous version of every file it touches, so\nundo works on all three. One catch: `codex`\n\nand `opencode`\n\nget that previous version from Git,\nso **undo needs your project to be a Git repo on those two**. Airship warns you at startup.\n\nAirship reuses whatever the chosen agent already has, and warns at startup if it finds nothing.\n\n| Agent | Needs one of |\n|---|---|\n`claude` |\n`ANTHROPIC_API_KEY` , `CLAUDE_CODE_OAUTH_TOKEN` , or a `claude` login (`~/.claude` ) |\n`codex` |\n`CODEX_API_KEY` , `OPENAI_API_KEY` , or a `codex login` (`~/.codex/auth.json` ) |\n`opencode` |\nthe `opencode` binary on PATH, plus a provider key or an `opencode auth login` |\n\nOpenCode is a separate install — `brew install sst/tap/opencode`\n\nor `npm i -g opencode-ai`\n\n—\nand accepts `ANTHROPIC_API_KEY`\n\n, `OPENAI_API_KEY`\n\n, `OPENCODE_API_KEY`\n\n, `OPENROUTER_API_KEY`\n\n,\n`GEMINI_API_KEY`\n\n, `GOOGLE_GENERATIVE_AI_API_KEY`\n\n, `AWS_BEARER_TOKEN_BEDROCK`\n\nor\n`AWS_ACCESS_KEY_ID`\n\n.\n\n**By default the agent runs unsandboxed.** It can write anywhere you can and reach the network —\nthe same access it has when you run it from your terminal. Pass `--safe`\n\nto confine it:\n\n| default | `--safe` |\n|\n|---|---|---|\n`codex` |\nfull access, network on | locked to your project folder, no network, no web search |\n`claude` |\nfull access, no sandbox | edits kept inside your project, dangerous commands blocked |\n`opencode` |\nfull access | asks before every edit and command, checked the same way; no web fetch, no web search, nothing outside your project |\n\n`--safe`\n\nis not equally strong on all three, and the CLI says so at launch:\n\n**Only** The operating system stops it writing outside your project. On`codex`\n\ngets a real sandbox.`claude`\n\nand`opencode`\n\n, Airship checks each edit and command first — a good check, but a check, not a wall.**That check looks for known-dangerous commands; it does not understand shell.** It catches`rm -rf`\n\n. It does not catch a write pointed somewhere else, like`echo x > /elsewhere`\n\n.Airship switches off their web tools, but nothing stops a command they run from opening a connection anyway. Only a sandbox can.`claude`\n\nand`opencode`\n\ncan still reach the network.\n\nIf a hard guarantee matters more to you than which agent you use, run\n`airship --agent codex --safe`\n\n.\n\nDiffs and undo work the same either way — `--safe`\n\nhas no effect on them.\n\n```\nairship [options]\nairship --target <port> [options]\nairship <command> [options]\n```\n\n| Command | |\n|---|---|\n`airship` |\nLaunch the visual editor against your dev server. Bare at a terminal, it asks first. |\n`airship init` |\nCreate an `airship.config.json` for this project. |\n`airship doctor` |\nCheck your environment and report what is wrong. |\n\nFlags accept `--flag value`\n\nand `--flag=value`\n\n, a camelCase spelling of any kebab name\n(`--maxTurns`\n\n≡ `--max-turns`\n\n), and `--no-<name>`\n\nto turn any boolean off. A bare `--`\n\nstops flag\nparsing — airship takes no positional arguments, so anything after it is ignored rather than\nforwarded.\n\n| Flag | Default | |\n|---|---|---|\n`-t, --target <port>` |\nPort your dev server is already running on. Detected from your `package.json` when omitted. |\n|\n`-p, --port <port>` |\nPort for the airship proxy. | `target + 1` |\n`--cwd <dir>` |\nProject root for edits. | current directory |\n`--mode <name>` |\nEditor mode: `canvas` or `inline` . Switchable from the editor too. |\n`canvas` |\n`--exec <command>` |\nStart your dev server with this command and stop it when airship exits. | |\n`--open` |\nOpen the editor in your browser once it is listening. |\n\n| Flag | Default | |\n|---|---|---|\n`-a, --agent <name>` |\nCoding agent: `claude` , `codex` , `opencode` . |\n`claude` |\n`-m, --model <id>` |\nModel id. | the agent's own default |\n`--effort <level>` |\nReasoning effort: `minimal` , `low` , `medium` , `high` , `xhigh` , `max` . |\n|\n`--max-turns <n>` |\nCap agent turns per edit (claude only). | `24` |\n`--max-budget <usd>` |\nStop an edit if it exceeds this cost in USD (claude only). | |\n`--commit` |\nAuto-commit each accepted edit (Conventional Commits). |\n\n`-m`\n\nis `--model`\n\n, not `--mode`\n\n. `--mode`\n\nhas no short alias.\n\n| Flag | Default | |\n|---|---|---|\n`--safe` |\nConfine edits to the project directory and cut network access. See\n|\n\n| Flag | Default | |\n|---|---|---|\n`--codex-path <path>` |\nPath to the `codex` binary. |\nbundled |\n`--codex-config <k=v>` |\nExtra `codex --config` pair; repeatable. |\n|\n`--opencode-path <path>` |\nPath to the `opencode` binary. |\nfound on PATH |\n`--opencode-url <url>` |\nAttach to a running `opencode serve` instead of starting one. |\n|\n`--opencode-agent <name>` |\nRun as a named opencode agent. | its own |\n`--opencode-config <file>` |\nJSON file merged into the opencode server config. |\n\n`--codex-config`\n\nreads the shape of the value: `true`\n\n/`false`\n\nbecome TOML booleans and anything\nnumeric becomes a number, so `--codex-config network_access=true`\n\nsends a boolean, not the string.\nQuote it — `--codex-config k='\"true\"'`\n\n— to keep a string a string.\n\n| Flag | |\n|---|---|\n`--json` |\nMachine-readable JSON on stdout, no colour and no banner. |\n`-q, --quiet` |\nSuppress the launch banner. Warnings still print. |\n`--debug` |\nPrint stack traces on failure. |\n`-h, --help` |\nShow this help. |\n`-v, --version` |\nPrint the version. |\n\nBanners, warnings and errors go to stderr; `--json`\n\npayloads, help and `--version`\n\ngo to stdout,\nso `airship --json | jq`\n\nis reliable.\n\nWrites an `airship.config.json`\n\nfrom the same questions the bare `airship`\n\nwizard asks, so it\nstops asking. Takes `--cwd`\n\nand the global flags. Needs a terminal.\n\nChecks, in order: `node`\n\n, `airship`\n\n, `config`\n\n, `git repo`\n\n, `overlay bundle`\n\n, `agent claude`\n\n,\n`agent codex`\n\n, `agent opencode`\n\n, `dev server`\n\n. Each reports `ok`\n\n, `warn`\n\nor `fail`\n\nwith a hint.\nOnly your preferred agent (`--agent`\n\n, default `claude`\n\n) can fail the run; the other two warn.\n\nExits `1`\n\nif any check failed, so `airship doctor && airship`\n\nworks. Takes `--cwd`\n\n, `--target`\n\n,\n`--agent`\n\nand the global flags.\n\n| Code | |\n|---|---|\n`0` |\nFine. |\n`1` |\nSomething failed. |\n`2` |\nBad flag, bad value, or a terminal was needed and there wasn't one. |\n`127` |\nNot an airship command. |\n`130` |\nInterrupted — Ctrl-C, or a cancelled prompt. |\n\nSettings resolve in this order, highest first:\n\n```\nflags  →  AIRSHIP_* environment  →  airship.config.json  →  defaults\n```\n\n`airship.config.json`\n\n, or an `\"airship\"`\n\nkey in your `package.json`\n\n. Run `airship init`\n\nto write\none. Every key is a flag name, in either kebab or camel case:\n\n```\n{\n  \"agent\": \"claude\",\n  \"mode\": \"canvas\",\n  \"target\": 3000,\n  \"safe\": true\n}\n```\n\nAirship looks for it from `--cwd`\n\nupwards and **stops at your repository root**, so a stray\nconfig file somewhere above your repo won't affect you. Misspell a key and it says so, with a\nsuggestion — it never quietly ignores one.\n\nEvery flag except `--help`\n\nand `--version`\n\nhas an environment variable: `AIRSHIP_`\n\nplus the flag\nname uppercased, with `-`\n\nas `_`\n\n.\n\n```\nAIRSHIP_TARGET          AIRSHIP_AGENT           AIRSHIP_CODEX_PATH\nAIRSHIP_PORT            AIRSHIP_MODEL           AIRSHIP_CODEX_CONFIG\nAIRSHIP_CWD             AIRSHIP_EFFORT          AIRSHIP_OPENCODE_PATH\nAIRSHIP_MODE            AIRSHIP_MAX_TURNS       AIRSHIP_OPENCODE_URL\nAIRSHIP_EXEC            AIRSHIP_MAX_BUDGET      AIRSHIP_OPENCODE_AGENT\nAIRSHIP_OPEN            AIRSHIP_COMMIT          AIRSHIP_OPENCODE_CONFIG\nAIRSHIP_SAFE            AIRSHIP_JSON            AIRSHIP_QUIET\nAIRSHIP_DEBUG\n```\n\n`AIRSHIP_HELP`\n\nand `AIRSHIP_VERSION`\n\nare deliberately not read — exporting one would leave the\nCLI unable to run anything. Booleans take `1`\n\n/`true`\n\n/`yes`\n\n/`on`\n\nor `0`\n\n/`false`\n\n/`no`\n\n/`off`\n\n;\nanything else is an error rather than a guess.\n\nThree more are honoured: `AIRSHIP_EDITOR`\n\n(`vscode`\n\n, `cursor`\n\n, `windsurf`\n\nor `zed`\n\n— which\neditor \"open in editor\" prefers, otherwise probed in that order), and `NO_COLOR`\n\n/ `FORCE_COLOR`\n\n.\n\n`--cwd`\n\nis the folder your dev server treats as its root, which is not always your repository\nroot. Airship needs it to turn the paths your dev server reports (`/src/app.tsx`\n\n) into real\nfiles on disk. In a monorepo where the app lives in `apps/web`\n\n, that's `--cwd apps/web`\n\n.\n\nLeave `--target`\n\noff and Airship works it out, trying each likely port in turn and taking the\nfirst one that answers:\n\n-\n**The port in your dev script**— a`--port`\n\n,`-p`\n\nor`PORT=`\n\nin`scripts.dev`\n\n,`scripts.start`\n\nor`scripts.serve`\n\n. -\n**Your framework's default**, by what is in your dependencies:Dependency Port `next`\n\n,`nuxt`\n\n,`@remix-run/dev`\n\n,`react-scripts`\n\n`3000`\n\n`parcel`\n\n`1234`\n\n`@angular/cli`\n\n`4200`\n\n`astro`\n\n`4321`\n\n`@sveltejs/kit`\n\n,`vite`\n\n`5173`\n\n`storybook`\n\n(or any`@storybook/*`\n\n)`6006`\n\n`gatsby`\n\n`8000`\n\n`@11ty/eleventy`\n\n`8080`\n\nMost specific first — a project with both\n\n`vite`\n\nand`storybook`\n\nis a Vite app that also has a component catalogue, not the other way round. -\n**Common ports**—`3000`\n\n,`5173`\n\n,`8080`\n\n,`4321`\n\n,`4200`\n\n.\n\nWith `--exec`\n\nit's the opposite: the port has to be *free*, since Airship is about to start your\ndev server on it. It won't start one on a port that's already taken.\n\nIncluding the ones with unflattering answers.\n\n**Do I need a plugin, or to change my build?**\nNo. Airship runs as a reverse proxy in front of your existing dev server. Nothing is added to\nyour dependencies, config, or bundle.\n\n**Does it work with Tailwind, CSS Modules or styled-components?**\nYes. Airship works with the styling system already in your project. It works with the tokens and\nstyling conventions already in your codebase, so visual changes can map back to the values your\ndesign system already uses.\n\n**How does it know which file an element came from?**\nDev builds already record where each thing on screen came from. Airship reads that to find the\nfile and line, and hands it to the agent.\n\n**What exactly gets sent to the agent?**\nWhat you clicked, the file and line it came from, anything you changed in the inspector, the\nframes you were working in — and whatever you typed.\n\n**Can I use my existing coding agent?**\nYes. Airship works with Claude Code, Codex, and OpenCode, so you don't need to change your agent\njust to use the visual editor.\n\n**Is it safe to point at a real repository?**\nAirship runs locally and works directly on the repository you point it at. By default your\ncoding agent has the same access to your files and the network that it always has. `--safe`\n\ncan\nkeep edits inside your project and block dangerous commands — read [Safety](#safety) for what it\ndoes and doesn't cover on each agent.\n\n**How do I undo something?**\nEvery edit can be undone from Airship, which keeps the previous version of the file. On `claude`\n\nthat's all there is to it. On `codex`\n\nand `opencode`\n\nthat previous version comes from Git, so\nthose two need your project to be a repository. See [Agents](#agents).\n\n**Can I see how a change affects different devices?**\nYes. Airship runs the same app at several real device sizes at once. Make a change once and\nwatch it land on desktop, tablet and mobile together, without resizing anything.\n\n**Can I use Airship without Git?**\nYes, Airship doesn't require it. But undo on `codex`\n\nand `opencode`\n\nworks by asking Git for the\nprevious version of the file, so without a repository you lose undo on those two. `claude`\n\nis\nunaffected. See [Agents](#agents).\n\n**Does my code leave my machine?**\nAirship runs entirely on localhost. It has no account, telemetry, or hosted service, and your\ncode isn't sent to Airship. Your chosen coding agent handles requests using the same credentials\nand provider it would use from your terminal.\n\nNode 22.13 or later, and one of Claude Code, OpenAI Codex or OpenCode.\n\n[airship.design](https://airship.design)[Issues](https://github.com/0xnyn/airship/issues)·[Releases](https://github.com/0xnyn/airship/releases)[CONTRIBUTING.md](/0xnyn/airship/blob/main/CONTRIBUTING.md)— architecture, the packages, Storybook, CI and releases[MIT](/0xnyn/airship/blob/main/LICENSE)", "url": "https://wpnews.pro/news/show-hn-airship-figma-like-visual-editor-for-claude-code-codex-and-opencode", "canonical_source": "https://github.com/0xnyn/airship", "published_at": "2026-08-11 01:09:14+00:00", "updated_at": "2026-08-11 01:41:30.497848+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "generative-ai"], "entities": ["Airship Labs", "Claude Code", "Codex", "OpenCode", "Vite", "Next", "Remix", "Rails"], "alternates": {"html": "https://wpnews.pro/news/show-hn-airship-figma-like-visual-editor-for-claude-code-codex-and-opencode", "markdown": "https://wpnews.pro/news/show-hn-airship-figma-like-visual-editor-for-claude-code-codex-and-opencode.md", "text": "https://wpnews.pro/news/show-hn-airship-figma-like-visual-editor-for-claude-code-codex-and-opencode.txt", "jsonld": "https://wpnews.pro/news/show-hn-airship-figma-like-visual-editor-for-claude-code-codex-and-opencode.jsonld"}}