Demo videos in pull requests
Automatically record your app in CI and attach a demo video to every PR.
Every opted-in PR gets a sticky comment with an inline GIF of the feature, linking to a full video on a shareable page. Reviewers see the change without checking out the branch.
Recommended setup
Run this once in the repo:
bashlittledemo setup --pr-demos --yes
The command always tells you what it will create. PR demo automation is opt-in:
plain littledemo setup --yes installs the public LittleDemo agent skill and
AGENTS.md guidance, but does not create a GitHub workflow.
Add LITTLEDEMO_API_KEY as a repo secret. If setup did not write a concrete
project id into the workflow, also add LITTLEDEMO_PROJECT_ID.
Commit the generated .github/workflows/littledemo-pr-demo.yml. By default it:
- runs on opened, synchronized, reopened, and ready-for-review PRs;
- records same-repo, non-draft PRs only;
- skips fork PRs because they cannot read repo secrets;
- updates one sticky PR comment instead of creating a new comment per push.
Manual workflow
The core of the generated workflow is:
yamlname: LittleDemo PR demoon: pull_request: types: [opened, synchronize, reopened, ready_for_review] workflow_dispatch:permissions: contents: read pull-requests: writejobs: demo: if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.draft == false && github.event.pull_request.head.repo.full_name == github.repository) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - run: npm ci - uses: seangeng/littledemo/action@v1 with: api-key: ${{ secrets.LITTLEDEMO_API_KEY }} project-id: ${{ secrets.LITTLEDEMO_PROJECT_ID }} start: npm run dev wait-on: http://localhost:3000 url: http://localhost:3000 prompt: "PR #${{ github.event.number }}: ${{ github.event.pull_request.title }}" duration: "10"
The action starts your dev server, waits for it, records a scroll tour with the LittleDemo engine, uploads the result with a thumbnail and GIF attached, uploads the MP4 as a workflow artifact, and posts one sticky comment that updates in place on every push — never a comment pile.
Scripted flows
Point the recording at the thing the PR actually changed with a checked-in steps file:
yamlwith: steps-file: .github/demo-steps.json
json{ "steps": [ { "action": "click", "text": "Settings" }, { "action": "click", "text": "Billing" }, { "action": "pause", "ms": 1500 } ]}
See Local recording for the full step schema.
Recording preview deployments
If your repo already deploys previews (Vercel, Netlify, or similar), skip booting the app in CI and record the preview URL when the deployment goes live:
yamlon: deployment_status:jobs: demo: if: github.event.deployment_status.state == 'success' runs-on: ubuntu-latest permissions: contents: read pull-requests: write steps: - uses: seangeng/littledemo/action@v1 with: api-key: ${{ secrets.LITTLEDEMO_API_KEY }} project-id: ${{ secrets.LITTLEDEMO_PROJECT_ID }} url: ${{ github.event.deployment_status.environment_url }} prompt: "Preview: ${{ github.event.deployment.ref }}"
deployment_status events carry no PR context, so the action finds the PR from
the commit automatically (or takes an explicit pr-number input).
Fork PRs
Forks can't read repo secrets. The setup-generated workflow skips fork PRs
before checkout so untrusted PR code cannot run with secrets. If you call the
Action directly and api-key or project-id is empty, the Action emits a notice
and exits green with the skipped output set to true, so required checks don't
block community PRs.
Without the action
The same flow is two CLI commands, usable in any CI system:
bashnpx --yes @littledemo/cli record http://localhost:3000 \ --upload --project "$LITTLEDEMO_PROJECT_ID" \ --prompt "PR demo" --yes --json > result.jsongh pr comment "$PR_NUMBER" --body "[)]($(jq -r .shareUrl result.json))"
GitHub strips iframes and has no video-embed API for comments, so an inline GIF linking to the share page is the ceiling — the GIF renders inline as long as it stays under GitHub's ~10 MB budget (the engine encodes at 640px/12fps to fit).