Skip to main content

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

tests License: MIT Python 3.10+

readme2demo running on its own repo — verified demo

▶ 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 with CLAUDE_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 covers claude -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 single GEMINI_API_KEY runs 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 export GEMINI_MODEL once. Install the extra: pip install 'readme2demo[gemini]'.
    • OpenAI (--openai [model]): same shape as Gemini — a single OPENAI_API_KEY powers the passes and the OpenHands agent, no model name is built in (--openai gpt-5.1 or export OPENAI_MODEL). Install the extra: pip install 'readme2demo[openai]'.
  • Optional: LLM_API_KEY + LLM_MODEL for --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. On pull_request it 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: push to the default branch and a cron are the honest triggers; a repo-path input 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:

  1. 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.md runs guide-only against an empty sandbox.
  2. The repo ships one (step_by_step.md / step-by-step.md at root or docs/, any case): same treatment, automatically.
  3. Neither exists: the pipeline generates a detailed step_by_step.md — every command from the verified commands.sh as 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

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!

Contributors

Contributors

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

readme2demo-0.7.1.tar.gz (21.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

readme2demo-0.7.1-py3-none-any.whl (100.4 kB view details)

Uploaded Python 3

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

Hashes for readme2demo-0.7.1.tar.gz
Algorithm Hash digest
SHA256 b91d2ddb7987d7d0ae04b3b087915df84837c116df6852809146f0343454da43
MD5 ea575fc73fb9b4b0436b897856cce9ae
BLAKE2b-256 6580b31b57323178cc7fe729573209fd5ebd52ba83577d001740607c6ce7ec17

See more details on using hashes here.

Provenance

The following attestation bundles were made for readme2demo-0.7.1.tar.gz:

Publisher: release.yml on alphacrack/readme2demo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for readme2demo-0.7.1-py3-none-any.whl
Algorithm Hash digest
SHA256 024becc8b40b5f2fcb8ebfa0888920ea7e6231ae568f8407c2a144ce1db3e163
MD5 6c5b28d1adc807bd9d936e61f97c9715
BLAKE2b-256 c67d22be764f72a7dbb9ab65ae9036756cf06093a0e89bebc9b9922f29cf1469

See more details on using hashes here.

Provenance

The following attestation bundles were made for readme2demo-0.7.1-py3-none-any.whl:

Publisher: release.yml on alphacrack/readme2demo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page