▶ readme2demo generating its own tutorial: an AI agent runs this repo's README in a sandbox, a fresh container replays every step, then the demo is rendered. Full self-run output in examples/readme2demo · run against another project in examples/toolhive.
AI-verified tutorial and demo video generator. Point it at a repo. An AI agent reads the README and actually runs it inside a hardened Docker sandbox. Only after a clean-room replay passes does it render a demo video (VHS) and publish the tutorial, step-by-step guide, and troubleshooting doc.
The value is not "AI writes a tutorial" — it's that the tutorial ran, twice, before you saw it.
See it in action: browse verified example runs — real tutorials, step-by-step guides, and demo videos, each independently replayed in a clean container before publishing.
repo URL → ingest/plan → agent run (in Docker) → normalize transcript
→ distill minimal path → VERIFY replay in fresh container
→ generate tutorial.md + troubleshooting.md → render VHS video
See architecture/README.md for the full architecture.
- Python ≥ 3.10, Docker
- Auth, one of:
- Your Claude subscription (no API key): a local Claude Code install. The planner/distiller/tutorial passes run on your subscription via
--llm-backend claude-cli(claude -p), and the in-sandbox agent authenticates withCLAUDE_CODE_OAUTH_TOKEN(create one:claude setup-token). Fully supported for self-hosted, single-operator runs against your own repos — Pro/Max plans include a monthly Agent SDK credit that coversclaude -p. ANTHROPIC_API_KEY— metered API billing; best for scale and concurrency, and required if you host readme2demo as a service for others (per Anthropic's terms, subscription auth may not power a multi-tenant product — see ROADMAP.md). Add--anthropic [model]to run the sandboxed agent on the OpenHands engine with a Claude model instead of claude-code.- Google Gemini (
--gemini [model]): a singleGEMINI_API_KEYruns the whole session off Claude — the planner/distiller/tutorial passes use Gemini and the sandboxed agent runs on the OpenHands engine (also on Gemini). No model name is built in (Google retires old ones with a hard 404): name it per run (--gemini gemini-3.5-flash) or exportGEMINI_MODELonce. Install the extra:pip install 'readme2demo[gemini]'. - OpenAI (
--openai [model]): same shape as Gemini — a singleOPENAI_API_KEYpowers the passes and the OpenHands agent, no model name is built in (--openai gpt-5.1or exportOPENAI_MODEL). Install the extra:pip install 'readme2demo[openai]'.
- Your Claude subscription (no API key): a local Claude Code install. The planner/distiller/tutorial passes run on your subscription via
- Optional:
LLM_API_KEY+LLM_MODELfor--engine openhands(experimental) with any other litellm provider — the presets above fill them automatically
# run on your Claude subscription (no API key) — supported for self-hosted runs
claude setup-token # interactive: approve in browser, then COPY the
# sk-ant-oat01-... token it prints (do NOT use $(...))
export CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-...
readme2demo run <repo-url> --llm-backend claude-cli
# run on metered API billing (scale, concurrency, or hosting for others)
export ANTHROPIC_API_KEY=sk-ant-...
readme2demo run <repo-url> # --llm-backend auto picks api
# run the whole session on Google Gemini (OpenHands agent + Gemini passes)
pip install 'readme2demo[gemini]'
docker build -t readme2demo/openhands:latest images/openhands # one-time: OpenHands sandbox image
export GEMINI_API_KEY=...
readme2demo run <repo-url> --gemini gemini-3.5-flash # model named per run
export GEMINI_MODEL=gemini-3.5-flash # ...or set once, then:
readme2demo run <repo-url> --gemini # bare flag reads GEMINI_MODEL
# run the whole session on OpenAI (OpenHands agent + OpenAI passes)
pip install 'readme2demo[openai]'
export OPENAI_API_KEY=sk-...
readme2demo run <repo-url> --openai gpt-5.1 # or export OPENAI_MODEL once
# run the OpenHands agent with a Claude model on API billing
export ANTHROPIC_API_KEY=sk-ant-...
readme2demo run <repo-url> --anthropic # uses the config model by defaultpip install -e ".[dev]"
docker build -t readme2demo/base:latest images/base/
docker build -t readme2demo/openhands:latest images/openhands/ # only for --engine openhands / --gemini / --openai / --anthropicreadme2demo run https://github.com/example/tool
readme2demo run -gr https://github.com/example/tool # same, via the flag
readme2demo run -s my_guide.md # guide-only: no repo, your guide is self-contained
readme2demo run -gr https://github.com/example/tool -s my_guide.md # both: your guide drives everything
readme2demo run https://github.com/example/tool --gemini gemini-3.5-flash # run on Google Gemini (needs GEMINI_API_KEY; uses the OpenHands agent; bare --gemini reads GEMINI_MODEL)
readme2demo run https://github.com/example/tool --openai gpt-5.1 # run on OpenAI (needs OPENAI_API_KEY; uses the OpenHands agent; bare --openai reads OPENAI_MODEL)
readme2demo run https://github.com/example/tool --anthropic # OpenHands agent with a Claude model on ANTHROPIC_API_KEY
readme2demo run https://github.com/example/tool --allow-docker-socket # for tools that manage containers (SECURITY TRADEOFF: pierces sandbox isolation — trusted repos only)
readme2demo run https://github.com/example/tool --skip-video --budget-usd 3
readme2demo resume runs/tool-20260702-... --from-stage render
readme2demo report runs/tool-20260702-...The repo is optional: pass it positionally or with -gr/--github-repo, supply a guide with -s/--step-by-step, or both. At least one is required. With a guide alone, no repo is cloned — the guide must be self-contained (install a published package, or clone what it needs as an explicit step); the fresh-container replay still verifies every command.
Outputs land in runs/<run-id>/: tutorial.md, step_by_step.md, troubleshooting.md, commands.sh, demo.tape, demo.mp4, demo.gif, howto.jsonld, plus manifest.json with stage statuses and total cost.
Get a red X when your README stops working. The repo-root composite action installs readme2demo from its own pinned checkout, builds the sandbox image, runs the full pipeline against your repo's URL, and fails the check when the fresh-container replay does not pass:
name: readme-check
on:
push:
branches: [main] # url mode tests the default branch HEAD — see the caveat below
paths: ["README.md"]
schedule:
- cron: "0 6 * * 1" # weekly: catch the world changing under an unchanged README
permissions:
contents: read
jobs:
verify-readme:
runs-on: ubuntu-latest
steps:
- uses: alphacrack/readme2demo@main # pin a tag or SHA once released
with:
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
skip-video: "true"⚠ URL mode only — this does NOT verify PR heads yet. The action clones the remote default branch HEAD of
repo-url(default: the repository running the workflow); ingestion accepts only https URLs,--depth 1, no ref pinning. Onpull_requestit would test the base branch's README — not the PR's — so don't wire it to PRs expecting a pre-merge verdict. Until #74 (local-path ingestion) lands,on: pushto the default branch and a cron are the honest triggers; arepo-pathinput for real PR-head verification arrives with it.
Cost: every run spends real agent money on your ANTHROPIC_API_KEY — typically a few dollars, hard-capped by budget-usd (default "5"; the run aborts if exceeded). The paths: filter plus a cron keeps spend proportional to README churn, and skip-video: "true" cuts wall-clock time (the render costs no API money either way).
The check fails in two distinguishable ways, named in the step log: README broken (pipeline completed, clean-room replay failed — detected via readme2demo report --json, because readme2demo run deliberately exits 0 on a completed-but-unverified run) and action infra broke (nonzero pipeline exit: preflight, budget, Docker). Outputs: verified ("true"/"false") and run-dir; tutorial.md, step_by_step.md, verify.log (and demo.gif when video is on) upload as the readme2demo-run artifact.
The demo video is always built from step_by_step.md: its steps are parsed, and every demo-safe, grounded command becomes a typed command in the video with the step title shown as an on-screen comment. Three ways it comes to exist, in priority order:
- You pass one:
readme2demo run <url> -s my_guide.md— injected into the clone as the authoritative guide; planner and agent follow it, video plays it. The<url>is optional here:readme2demo run -s my_guide.mdruns guide-only against an empty sandbox. - The repo ships one (
step_by_step.md/step-by-step.mdat root ordocs/, any case): same treatment, automatically. - Neither exists: the pipeline generates a detailed
step_by_step.md— every command from the verifiedcommands.shas a numbered step with real captured outputs — then builds the video from it. Ready to contribute back to the repo.
Setup steps (clones, installs, builds) are documented in the guide but kept out of the video — it plays against the verified, already-built worktree, showing the payoff.
Every tutorial carries a verification badge: ✅ Verified on <date> · image <digest> · commit <sha> — or a loud ⚠ UNVERIFIED if the replay didn't pass. Unverified output is never silently published.
CLI flags > readme2demo.toml > defaults:
engine = "claude-code" # or "openhands"
model = "claude-sonnet-5" # planner/distiller/tutorial passes
llm_backend = "auto" # auto | api | claude-cli | gemini | openai
max_turns = 60
budget_usd = 5.0
base_image = "readme2demo/base:latest"
skip_video = falsepython -m pytest tests/ -q # comprehensive unit test suite, no docker/network needed
ruff check src/ tests/ # correctness lint (matches CI)
python -m pytest -m integration # requires docker + API keys (none yet)READMEs are untrusted code. The agent runs inside a hardened container (cap-drop ALL, no-new-privileges, memory/cpu/pids limits, non-root) — that container is the permission boundary. Known MVP tradeoff: the API key enters the sandbox; use a dedicated low-limit key. A host-side key-injecting egress proxy is planned (Milestone 4).
Full threat model and private vulnerability reporting: SECURITY.md.
- Examples — verified output committed as proof
- Roadmap — where this is headed (including the exploratory hosted/SaaS direction)
- Contributing — the one non-negotiable rule, and how to get set up
- Security policy · Code of Conduct
- Architecture — stage boundaries and diagrams
MIT licensed. The CLI and verification pipeline are, and will stay, free and open source.
A huge thank you to everyone who has contributed to readme2demo!
