Verified tutorials and demo videos from your README. An AI agent runs it in a hardened Docker sandbox and replays it in a fresh container before anything is published.
Project description
readme2demo — verified tutorials & demo videos from your README
▶ 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.
How it works
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.
Requirements
- 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 default
Install
pip 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 / --anthropic
Usage
readme2demo 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, plus manifest.json with stage statuses and total cost.
GitHub Action — verify your README in CI
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.
step_by_step.md — the video's source
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.
Configuration
CLI flags > readme2demo.toml > defaults:
engine = "claude-code" # or "openhands"
model = "claude-sonnet-5" # planner/distiller/tutorial passes
max_turns = 60
budget_usd = 5.0
base_image = "readme2demo/base:latest"
skip_video = false
Development
python -m pytest tests/ -q # 175 unit tests, no docker/network needed
ruff check src/ tests/ # correctness lint (matches CI)
python -m pytest -m integration # requires docker + API keys (none yet)
Security model
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.
Project & community
- 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.
Contributors
A huge thank you to everyone who has contributed to readme2demo!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file readme2demo-0.7.1.tar.gz.
File metadata
- Download URL: readme2demo-0.7.1.tar.gz
- Upload date:
- Size: 21.0 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b91d2ddb7987d7d0ae04b3b087915df84837c116df6852809146f0343454da43
|
|
| MD5 |
ea575fc73fb9b4b0436b897856cce9ae
|
|
| BLAKE2b-256 |
6580b31b57323178cc7fe729573209fd5ebd52ba83577d001740607c6ce7ec17
|
Provenance
The following attestation bundles were made for readme2demo-0.7.1.tar.gz:
Publisher:
release.yml on alphacrack/readme2demo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
readme2demo-0.7.1.tar.gz -
Subject digest:
b91d2ddb7987d7d0ae04b3b087915df84837c116df6852809146f0343454da43 - Sigstore transparency entry: 2201034131
- Sigstore integration time:
-
Permalink:
alphacrack/readme2demo@5267cfd793ae969d1d2f1956092750ba6d89a557 -
Branch / Tag:
refs/tags/v0.7.1 - Owner: https://github.com/alphacrack
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5267cfd793ae969d1d2f1956092750ba6d89a557 -
Trigger Event:
push
-
Statement type:
File details
Details for the file readme2demo-0.7.1-py3-none-any.whl.
File metadata
- Download URL: readme2demo-0.7.1-py3-none-any.whl
- Upload date:
- Size: 100.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
024becc8b40b5f2fcb8ebfa0888920ea7e6231ae568f8407c2a144ce1db3e163
|
|
| MD5 |
6c5b28d1adc807bd9d936e61f97c9715
|
|
| BLAKE2b-256 |
c67d22be764f72a7dbb9ab65ae9036756cf06093a0e89bebc9b9922f29cf1469
|
Provenance
The following attestation bundles were made for readme2demo-0.7.1-py3-none-any.whl:
Publisher:
release.yml on alphacrack/readme2demo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
readme2demo-0.7.1-py3-none-any.whl -
Subject digest:
024becc8b40b5f2fcb8ebfa0888920ea7e6231ae568f8407c2a144ce1db3e163 - Sigstore transparency entry: 2201034159
- Sigstore integration time:
-
Permalink:
alphacrack/readme2demo@5267cfd793ae969d1d2f1956092750ba6d89a557 -
Branch / Tag:
refs/tags/v0.7.1 - Owner: https://github.com/alphacrack
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5267cfd793ae969d1d2f1956092750ba6d89a557 -
Trigger Event:
push
-
Statement type: