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.2.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.2-py3-none-any.whl (100.8 kB view details)

Uploaded Python 3

File details

Details for the file readme2demo-0.7.2.tar.gz.

File metadata

  • Download URL: readme2demo-0.7.2.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.2.tar.gz
Algorithm Hash digest
SHA256 6e8a712fefb323d32cc10eb4d54416784146f89bac92d63bf4eb25acff165525
MD5 dedeb321c33c4e2e9efea8a6a2bcf3a5
BLAKE2b-256 fbe530449a16818cc274d223607bd9d11f023269ed48f31059a4539694c1f31c

See more details on using hashes here.

Provenance

The following attestation bundles were made for readme2demo-0.7.2.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.2-py3-none-any.whl.

File metadata

  • Download URL: readme2demo-0.7.2-py3-none-any.whl
  • Upload date:
  • Size: 100.8 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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 873e7f999764694b735fb7b26a413296fd70450e79b51d316acf3278f3cf1255
MD5 6232ecbc267a361fe86e29fd86789448
BLAKE2b-256 84d69831af4d4a534dbf0d1025deb7ac81a87d253762a02b3f0c7ac4be7a2bfd

See more details on using hashes here.

Provenance

The following attestation bundles were made for readme2demo-0.7.2-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