Specreel — instructions for AI agents

You are reading this because someone asked you to set up Specreel for their web app, or to run its demos/tests. This page is written for you (an AI coding tool such as Claude Code, Cursor, Codex, or an agent built on the Claude or OpenAI APIs). Follow it as a checklist; relay the "ask the user" points verbatim.

What Specreel is: it opens a web app in a real browser, turns its flows into narrated, shareable demos, and re-runs them on a schedule — so the demos are also end-to-end tests and can't go stale. Hosted at https://app.specreel.dev; the engine is open source (pip install specreel).

Pick the path

The user has… Do
a deployed app (staging or production URL) and wants hosted demos that re-check themselves Path A — hosted (below). No code, no CI.
an app running locally, or wants the demo as files / in their own CI Path B — the open-source CLI (bottom of this page).

Path A — hosted (Specreel Cloud)

1. Get an API token

Ask the user:

Open https://app.specreel.dev/app/tokens (sign up is free; it includes a 14-day Team trial), click Create token, and paste the token (it starts with scl_) to me.

Keep the token out of files you commit and out of your replies. Send it on every request as Authorization: Bearer <token>.

2. Connect — MCP (preferred) or the JSON API

As an MCP server the operations are typed tools (whoami, scan_url, create_project, set_signin, add_scenario, run_project, run_status, get_project):

# Claude Code
claude mcp add --transport http specreel https://app.specreel.dev/mcp \
  --header "Authorization: Bearer scl_…"

Cursor / Claude Desktop (mcp.json): {"mcpServers": {"specreel": {"url": "https://app.specreel.dev/mcp", "headers": {"Authorization": "Bearer scl_…"}}}}. OpenAI Responses API: a tool of type: "mcp" with server_url https://app.specreel.dev/mcp and that Authorization header. Any client that can send a header works; the server is stateless Streamable HTTP.

Or call the JSON API directly (reference below) — same operations, same token.

3. Create the project from the app's URL

create_project(url) (or POST /api/v1/projects {"url": …}) opens the app in a browser, finds demo-worthy flows (forms, search, navigation) and creates a project with one editable scenario per flow. It takes 30–90 seconds; wait for it.

Add flows the user describes in plain English with scenarios: ["sign in and create a project named Acme", …] (at creation) or add_scenario later — they're generated and checked in a real browser.

4. If the reply says login.needed — ask HOW the app signs in

A sign-in wall is normal. Ask the user which of these fits, then call set_signin (or pass the same fields to create_project again):

The app signs in with… Send
its own email + password form login_url, login_user, login_password of a dedicated test account (never a real customer's). The steps are detected automatically.
Google / GitHub / SSO, or a magic link (nothing to type) session — a signed-in session of the test account. The reliable way: run npx playwright codegen --save-storage=auth.json <login url>, ask the user to sign in in the browser window that opens (OAuth and magic links work there) and close it, then send the contents of auth.json as the session string. Alternatively the user can paste the app's Cookie header from their own browser. Only cookies and storage for the app's own domain are kept — the Google / GitHub session the file also holds is discarded before anything runs. A file with no cookies for the app's own domain is refused on the spot (400, error + session.domains = the domains it does hold): the sign-in has to finish on the app itself, not only at the provider — then send that auth.json.
a sign-in link (a staging test-login route like /test-login?key=…) login_url alone, no password. It's just opened before every run.

Or public_only: true to create the project from the public pages only. Sessions expire eventually: a later run then reports blocked_by_signin for the affected flows — capture a fresh session and set_signin again.

5. Run it and report

run_project → poll run_status (every ~10 s; an isolated browser takes ~30–60 s to spin up first) until done is true. Then tell the user:

  • the gallery_url — the shareable, narrated demo;
  • which flows failed (flows[].failed), with the hint if there is one;
  • blocked_by_signin flows mean the run wasn't signed in — go back to step 4.

Failed flows are usually either a scenario worth rewording (add_scenario with a clearer description, then pause the old one in the app) or a real bug in the app — say which you think it is, and don't guess silently.

A scenario with status: "draft" isn't run at all: its generated steps failed their first run in a real browser, or came back as a placeholder because the pages it needs weren't found (usually the sign-in didn't take). Tell the user, fix the sign-in if that's the cause, and add it again with a clearer description. A draft with generated: false has no steps yet (imported from a gallery, or generation failed): the user regenerates it in the app (Edit → Save & regenerate).

Rules

  • Use a test account and never run flows that buy, delete or email real customers. The flows run for real against the URL you give.
  • Don't paste tokens, passwords or sessions into chat, commits or logs.
  • If something needs a human (an OAuth sign-in, a choice of flows), ask — don't improvise credentials.

JSON API reference

Base https://app.specreel.dev. JSON bodies in, JSON out. Errors are {"error": "…"} with 400/401/402/403/404/409. A project may be referenced by id or slug.

Method & path Body Returns
GET /api/v1/me — workspace, plan, token role, projects
POST /api/v1/scan url, optional sign-in fields flows[], login{needed, login_url, reason, options}
POST /api/v1/projects url, name?, flows? (from scan), scenarios? (English strings), lang? (py/js), sign-in fields, public_only?, idempotency_key? (or an Idempotency-Key header) 201 {created, project, next} — or 200 {created:false, login{needed…}} — or, for a retry of a create that already ran (same key, or no key and the same name + url within 2 minutes), 200 {created:false, existing:true, project}
GET /api/v1/projects/<id\|slug> — project with scenarios[] (status, verify_state, draft, generated), signin.method, last_run, gallery_url
POST …/signin login_url, login_user, login_password, session, steps?, clear_session? {ok, signin} (owner/admin tokens)
POST …/scenarios description (English), folder? 201 {scenario{id, generated, verifying}}
POST …/run — 202 {id, status_url, note} · 409 if a run is in progress · 403 with the reason if the plan blocks it
GET …/runs/<id> — {status, done, flows[{slug,title,failed,blocked_by_signin}], blocked_by_signin[], hint, gallery_url, log_tail}
POST /api/v1/publish multipart: project, gallery (zip), flows what the CLI's specreel publish --to cloud sends

Sign-in fields: login_url, login_user, login_password, session.

Path B — the open-source CLI (local app, or files you control)

pip install specreel playwright && playwright install chromium
specreel recommend http://localhost:3000        # scaffolds specreel_flows.py
python specreel_flows.py                         # runs the flows → test-results/*/trace.zip
specreel test-results -o site --bundle           # → site/index.html + site/gallery.html
specreel publish site --to cloud --project my-app --token scl_…   # or --to ghpages

Finish the TODOs in specreel_flows.py with the user (only they know what "this worked" means). A local MCP server (pip install "specreel[mcp]", command specreel-mcp) exposes the same CLI as tools; the Claude Code skill in integrations/claude-code/specreel/ scripts the whole loop. Behind a login locally: specreel recommend <url> --storage-state auth.json (from playwright codegen --save-storage), or --login-url <url> with SPECREEL_LOGIN_USER / SPECREEL_LOGIN_PASSWORD in the environment.

Docs for humans: https://app.specreel.dev/docs · Source: https://github.com/specreel/specreel