# CodeRush.run A creative coding studio in your browser. Paste anything — HTML, JavaScript, TypeScript, Markdown, JSX, TSX, SVG, XML, CSS, JSON — and it runs at once in a private sandbox. An optional "Review first" mode pauses pages with JavaScript or outside connections for approval. A Chrome extension, a hosted pad, and a local agent service. Hosted pad: https://coderush.run The hosted pages record usage with BetterMeter through a first-party proxy at `/bm/`: page visits and named events (run, paste, view, template, ai_request, rush_created) with small facts such as the detected format. An event never contains snippet source, Rush fragments, API keys, passwords or prompts. Quick guide: https://coderush.run/guide Runnable templates: https://coderush.run/templates Demos (20 three.js scenes, 12 games; open any with /?demo=): https://coderush.run/demos The hosted pad keeps up to 24 local snapshots. Restoring one first checkpoints an unsaved current draft and offers Undo; if the browser cannot store that recovery copy, it leaves the editor unchanged. Files optionally separates index.html, style.css and script.js in local browser storage, then combines one annotated HTML document for the existing preview-safety, snapshot and Rush-link paths. Problems loads only when opened, parses source locally without executing it, reports syntax and common accessibility gaps by file and line, and jumps back to the issue. ## For AI agents You generate UI. You are blind to it. A screenshot fixes half of that: a vision model can say a page LOOKS wrong. It cannot see an uncaught error or a failed request, tell a dark scene from a canvas that never drew, measure how far content overflows or how much text is cut off, or know which line produced what it sees. So do not choose between a screenshot and measurement. A CodeRush check returns both: the screenshots, the facts a picture cannot show, and for HTML source the line each element was written on plus the CSS rules behind each finding. Every report carries a `brief` written for a vision model: facts first, then where things are on the screenshot, then a request for only what measurement cannot see. The model judges what looks wrong; the report says why and where. It runs on your machine, keeps nothing, calls no model, and works with any model. Three ways in, one engine and one report format: - **MCP server** (stdio) with tools `check`, `interact`, `share` and `status`. - **Command line**: `coderush-run check `. It prints JSON when piped and exits 0 for no problems, 1 for problems found, 2 when the command failed. - **Local HTTP service** on 127.0.0.1:8765: `POST /check`, `/interact`, `/share`, plus the older `/render` and `/run`. Install: the npm package `coderush-run` is not published yet. From a checkout of https://github.com/arbourfr/coderush-run, run `npm install`, then `node tools/coderush.mjs …`, `node tools/mcp.mjs` or `npm run serve`. Claude Code: `claude mcp add coderush -- node /path/to/coderush-run/tools/mcp.mjs`. A browser comes from Playwright's Chromium, or from the installed Google Chrome when Chromium was never downloaded. ### The loop 1. Write or change the UI. 2. `check` it, and read `hint` first. It names the most important problem and how to fix it. 3. Look at the screenshots with `brief`: the facts are measured, so trust them over how an image looks, and judge what they cannot see (cramped, overlapping, misaligned, unreadable). Findings carry `line` and `rules`, so edit there. 4. Fix, then check again, until `ok` is `true`. 5. Before calling UI work done, check at `viewports: [390, 1280]` and `themes: ["light", "dark"]`. 6. To test behaviour, `interact` using refs from the report (`@e1`, `@e2`…), then read `compare.verdict`. ### check — input ```json { "source": "function App(){ return

Hi

}", // or "url": "http://localhost:5173" "kind": "jsx", // html js ts markdown jsx tsx svg xml css json; detected when left out "viewports": [390, 1280], // widths or {"width":390,"height":844}; default [1280] "themes": ["light", "dark"], // default ["light"]; viewports × themes ≤ 6 "steps": [{"fill":"@e1","text":"hi"}, {"click":"@e2"}], "frames_ms": [500, 1500], // extra screenshots after the first, for animation "net": "cdn", // "cdn" (default) | "none" | "all" | ["api.example.com"] "full_page": false, "wait_ms": 600, "timeout_ms": 30000, "compare_to": "c_…" } ``` Steps: `{"click":t}` `{"fill":t,"text":"…"}` `{"press":"Enter"}` `{"press":"Tab","target":t}` `{"hover":t}` `{"select":t,"value":"…"}` `{"scroll":t}` `{"scroll":{"y":600}}` `{"wait_ms":500}` `{"wait_for":"text=Done"}`. A target `t` is a ref from the last report or a Playwright selector (`text=Save`, `#id`). Network: `"cdn"` allows public code CDNs (cdnjs.cloudflare.com, cdn.jsdelivr.net, unpkg.com, esm.sh, esm.run, ga.jspm.io, cdn.skypack.dev, code.jquery.com, cdn.tailwindcss.com, fonts.googleapis.com, fonts.gstatic.com) and blocks every other host. A URL check always reaches its own origin. Blocked requests are reported, never hidden. Files: the command line checks a file with its own folder behind it, so `style.css` and `logo.png` load; hidden files (`.env`) and anything outside the folder never do. The MCP tool takes the folder as `base_dir`. The HTTP service does not read folders. ### check — report ```json { "ok": false, "id": "c_QVK-WdFa", "kind": "jsx", "problems": 1, "hint": "At 390px wide the page is 620px wide, so it scrolls sideways: div#root > main > div reaches 620px.", "errors": [{"message": "…", "where": "…"}], // uncaught; where is "compile" or "mount" for CodeRush's own notices "console": {"errors": 0, "warnings": 1, "logs": 2, "entries": [{"type":"warning","text":"…","at":["390×844 dark"]}]}, "network": {"policy": "cdn", "quiet": true, "failed": [{"url":"…","status":404}], "blocked": ["https://…"]}, "shots": [{"viewport": "390×844", "theme": "light", "image": "…", "blank": false, "flat_color": null, "layout": {"page_width": 620, "overflow_x": true, "sticking_out": [{"selector":"div.wide","right":1400,"line":16,"rules":[{"selector":".wide","line":7,"properties":["width: 1400px"]}]}], "broken_images": [], "unreadable_text": [{"selector":"h1","text":"Settings","color":"#222222","background":"#111111","contrast":1.19,"line":12,"rules":[…]}], "clipped_text": [{"selector":"p.tag","text":"A label far too long","how":"cut","shows":[120,18],"needs":[264,18],"line":17,"rules":[…]}], "small_targets": [{"selector":"button.tiny","size":[14,14],"line":19,"rules":[…]}], "map": [{"selector":"h1.ok","box":[0,21,390,37],"line":15,"text":"Pricing"}]}}], "source_lines": true, // lines are exact for HTML source; other kinds say line null "brief": "CodeRush check · html · 3 problems\n\nMEASURED IN A REAL BROWSER. These are facts; …\nWHERE THINGS ARE in shot-0 …\nYOUR JOB: …", "a11y": ["heading[1] \"Todo\"", "textbox \"New task\" @e1", "button \"Add\" @e2"], "text": "Todo\nNew task Add", "steps": [{"step": "click @e2", "ok": true}], "compare": {"to": "c_…", "changed_pixels": 501, "box": {"x":67,"y":159,"width":241,"height":55}, "a11y": {"added": [], "removed": []}, "verdict": "0.2% of the screenshot changed, inside 241×55 at (67, 159). The list of controls did not change."}, "timing": {"total_ms": 3177, "timeout_ms": 18200, "wait_ms": 600} } ``` `image` is a URL (HTTP; `?images=inline` for base64), an attached image (MCP; `images: "all" | "problems" | "none"`), or a file path (command line, next to `report.json` in `--out`). A problem is any of: an uncaught error, a console error, a failed or blocked request, a failed step, a blank page, a one-colour screenshot, sideways overflow, a broken image, text with contrast under 3:1, text cut off by its box (`how` is `cut` or `spills`; an `ellipsis` or `line-clamp` is listed but is not a problem), or a tap target under 24×24px. `small_targets` follows WCAG 2.2's exemptions: a link inside a sentence, a form field with its own label, and a control whose size the author never set are not reported. `line` is the line in your HTML source where the element starts. `rules` are the CSS rules that apply to the element and set the properties behind the finding, with the line each starts on (`null` for external stylesheets, which carry `file` instead), and `when` for rules inside `@media` or `@container`. `map` lists what a person would point at on that screenshot, flagged elements first: selector, `box` as [x, y, width, height] in screenshot pixels, line and text. `brief` is the report written for a vision model looking at the screenshots: the measured facts first, marked as facts; then the map of shot-0; then a request to report, by selector, what measurement cannot see. Send it with the images. The command line also writes it to `brief.txt` in `--out` and prints it with `--brief`. ### interact, share, status - `interact {id, steps}` replays the check with its earlier steps, then the new ones, and compares with that check. Refs come from the first viewport. - `share {id}` makes a link a person can open: JavaScript stays off until they choose to run it. Nothing is shared unless you ask. - `status` lists formats, limits, the CDN list, step actions and recent check ids. ### HTTP service ``` npm run serve # → http://127.0.0.1:8765, prints where its token is export CODERUSH_TOKEN=$(node tools/coderush.mjs token) curl -s -X POST http://127.0.0.1:8765/check -H "Authorization: Bearer $CODERUSH_TOKEN" \ -H 'Content-Type: application/json' -d '{"source":"

hello

","viewports":[390,1280]}' ``` POST requests and `GET /status` need `Authorization: Bearer `. The token is written to `~/.coderush/.json`, readable by this user only, and deleted when the service stops. `CODERUSH_OPEN=1` turns the check off. Every request must name this machine in `Host` (127.0.0.1, localhost or ::1 with the port), and a foreign browser `Origin` gets 403. `GET /health` stays open. #### POST /render → image/png (older) ```bash curl -X POST http://127.0.0.1:8765/render -H "Authorization: Bearer $CODERUSH_TOKEN" \ -H 'Content-Type: application/json' -d '{"html":"

hello

"}' --output out.png # options via query or json: kind, width, height (320–2560), fullPage, wait (ms after the network goes quiet, default 600, max 5000) # WebGL works: three.js pages render through software GL, no GPU needed ``` Response headers: `X-Render-Kind`, `X-Render-Id`, `X-Render-Url`. #### POST /run → JSON (older) ```bash curl -X POST http://127.0.0.1:8765/run -H "Authorization: Bearer $CODERUSH_TOKEN" \ -H 'Content-Type: application/json' -d '{"html":""}' # → {"id":"...","kind":"html","url":"http://127.0.0.1:8765/s/...","logs":[{"type":"log","text":"42"}],"errors":[]} ``` #### GET /s/:id → text/html Every successful `/render` and `/run`, and every `/check` passed to `/share`, can be opened here. Failed or timed-out work has no share URL. Shares always render with JavaScript off in a credentialless, forced-sandbox iframe and provide Stop, safe reload, and exact-source download. Executable validation stays in the disposable worker. #### GET /health → {"ok":true,"activeRenders":0} #### GET /llms.txt → this file ### What is kept, and what is not protected - Checks live in the memory of the process that ran them (the last 50, and up to 200 MB of screenshots), and vanish when it exits. The command line writes only to `--out`. The HTTP service writes only its token file. - Every render is a fresh browser process with a hard deadline. Inline loops stop after 3 seconds of looping. - The network policy covers http(s) and WebSocket requests from the page. It does not stop DNS lookups, and an allowed host is a channel out: anything the page can read, it can send there. - The contrast check skips text over background images. Nothing is clicked unless you pass steps: a check measures a page after it settles. ### Extension (human surface) - **Hosted pad**: `Alt+R` or popup → "Full paste pad" opens https://coderush.run. Paste anything, iterate through a user-selected AI provider, or create a public, private, or password-protected Rush link. - **Enabled sites**: after the user grants the named site in the popup, code blocks that hold HTML get a ▶ Run button. Installation has no blanket website access; turning the site off removes the controls and permission. The context-menu "Run this HTML" on a selection needs no page grant. - **Runner tab**: shows the result in a sandboxed iframe, with Stop, source (editable, `Apply & rerun`), an interactive console drawer, kind chip, copy/save. Before approving active content, Run offline preserves the visible HTML and inline CSS in a separate iframe with no script, form, popup or external-network capability. Console commands execute only in the current active sandbox, await promises, keep 50 tab-only history entries and share the three-second inline-loop budget. Stalled renders stop at five seconds. - **Safe Mode**: add `?safe=1` to render HTML and inline CSS with no script, form, popup or external-network permission. Source stays preserved until the user explicitly reviews and enables active content. ### Formats | Kind | How it runs | |------|-------------| | html | sandboxed document.write | | js | generated sandbox document, runs at once; known globals (THREE, d3, p5, Chart, gsap, anime, lodash, dayjs, jQuery, Matter, PIXI, Tone, Phaser) are loaded from cdnjs when the script does not import them | | ts | plain TypeScript, types stripped with Babel, then run like js | | markdown | marked → styled article | | jsx / tsx | Babel + React 18 (vendored, offline), auto-mounts last component | | svg | centered on checkerboard stage | | xml | indented, color-coded source view | | css | demo page of bare elements | | json | pretty-printed, syntax-colored | ### Tips for agents - Prefer `kind` explicit when you know the format; detection is good but explicit is cheaper. - JSX: no imports needed — `React`, hooks (`useState`, `useEffect`, …) and `ReactDOM` are pre-wired. `export default` is stripped, last capitalized component auto-mounts. If you call `createRoot` yourself we leave you alone. - Keep snippets under 4MB. - Inline classic/module scripts are loop-guarded: a loop stops after 3 seconds of looping, and time the page spent blocked outside loops does not count. Every agent render also gets a disposable browser process and a hard deadline, so external scripts, `eval` and `Function` cannot poison the next render. On the human surfaces those paths cannot be rewritten; use Stop or `?safe=1` when recovering untrusted source. - Use `check` for everything; `/render` and `/run` remain for existing callers. ## Repo https://github.com/arbourfr/coderush-run — `extension/` is the shipped product (no build step, `chrome://extensions` → Load unpacked). `npm install && npm test` runs all suites (unit + real Chrome + agent service).