بنقرة واحدة
vhs-tape-authoring
// Use when creating new VHS demo tapes or editing existing ones. Covers tape syntax, setup scripts, mock-gh data layout, and the checklist for adding a new demo end-to-end.
// Use when creating new VHS demo tapes or editing existing ones. Covers tape syntax, setup scripts, mock-gh data layout, and the checklist for adding a new demo end-to-end.
Complete YAML schema reference for File and FileSet resources. Use when writing manifests to manage files (CODEOWNERS, LICENSE, CI workflows, etc.) in one or more repositories, including templating, patches, reconcile modes, delivery method, and import-into behavior.
Complete YAML schema reference for Repository and RepositorySet resources. Use when writing or editing manifests for repo settings, labels, actions, branch protection, rulesets, secrets, variables, or repository defaults.
CI/CD integration patterns for gh-infra: auto-apply on merge, scheduled drift detection, self-managed vs central-management layouts, and authentication setup for GitHub Actions workflows.
Overview of gh-infra and command workflow (import, validate, plan, apply). Use when managing GitHub repository settings, labels, actions settings, rulesets, secrets, variables, or files declaratively via YAML manifests.
Use when pulling live GitHub state back into existing gh-infra manifests with `gh infra import --into`, especially for write/patch/skip decisions, shared file sources, template-backed files, and import safety rules.
Use when running demo recordings, diagnosing recording failures, or regenerating GIFs from existing MP4s. Covers the Docker + VHS + ffmpeg pipeline.
| name | vhs-tape-authoring |
| description | Use when creating new VHS demo tapes or editing existing ones. Covers tape syntax, setup scripts, mock-gh data layout, and the checklist for adding a new demo end-to-end. |
Use this skill to create or edit VHS tape files and their supporting setup scripts for gh-infra demos.
Every .tape follows this pattern:
# 1. Output targets
Output demo-<name>.gif
Output demo-<name>.mp4
# 2. Theme and layout
Set Theme { ... }
Set Shell "bash"
Set FontSize 20
Set Width 1400
Set Height 900
Set Padding 20
Set WindowBar ""
Set TypingSpeed 50ms
# 3. Hidden setup
Hide
Type "source /data/setup-<name>.sh"
Enter
Sleep 2s
Type "clear"
Enter
Sleep 500ms
Show
# 4. Visible demo sequence
Sleep 700ms
Type "gh infra ..."
Enter
Sleep 3s
# ... more actions ...
Sleep 2s
Two themes are available. Copy from an existing tape:
| Theme | Based on | Use in |
|---|---|---|
gh-infra-dark | Tokyo Night | All tapes except light variant |
gh-infra-light | Tokyo Night Day | demo-light.tape only |
| Command | Usage | Notes |
|---|---|---|
Type "text" | Types text into terminal | Respects TypingSpeed |
Enter | Press Enter | |
Escape | Press Escape | |
Tab | Press Tab | |
Sleep 1s | Wait | Use ms or s units |
Hide / Show | Toggle recording visibility | Setup runs in Hide |
Output <file> | Set output file | Always set both .gif and .mp4 |
| Action | Recommended Sleep |
|---|---|
After source setup-*.sh | 2s |
After clear | 500ms |
| Before first command | 700ms-1s |
After Type before Enter | 350ms-500ms |
After running gh infra plan/apply | 5s-8s (depends on output size) |
After confirmation (y + Enter) | 5s-6s |
| End of demo | 2s-3s |
Each tape has a corresponding setup-<name>.sh:
#!/usr/bin/env bash
set -euo pipefail
# 1. Install gh-infra binary
cp /data/.gh-infra /usr/local/bin/gh-infra
chmod +x /usr/local/bin/gh-infra
# 2. Create gh wrapper (routes "gh infra" to real binary, rest to mock)
cat > /usr/local/bin/gh << 'WRAPPER'
#!/usr/bin/env bash
if [[ "$1" == "infra" ]]; then
shift
exec /usr/local/bin/gh-infra "$@"
fi
exec /data/mock-gh "$@"
WRAPPER
chmod +x /usr/local/bin/gh
# 3. Populate mock data
export MOCK_DIR=/tmp/mock-data
mkdir -p "$MOCK_DIR/<owner>/<repo>"
cat > "$MOCK_DIR/<owner>/<repo>/view.json" << 'JSON'
{ ... }
JSON
# 4. Create demo working directory and manifests
mkdir -p /tmp/demo
cat > /tmp/demo/<manifest>.yaml << 'YAML'
...
YAML
# 5. Set prompt
export PS1='$ '
The gh wrapper is the key mechanism:
gh infra ... → real gh-infra binary (spinners, diffs, colors are genuine)gh repo view ..., gh api ... etc. → mock-gh returns prepared datamock-gh is data-driven and scenario-agnostic. It reads from $MOCK_DIR:
$MOCK_DIR/{owner}/{repo}/
view.json # gh repo view --json response
commit-settings.json # squash/merge commit title/message (optional)
contents/{path} # raw file content (base64-encoded on the fly)
| gh command pattern | Data source | Default if missing |
|---|---|---|
repo view --json description,... | view.json | Empty/default settings |
repo view --json defaultBranchRef | hardcoded | "main" |
REST /actions/permissions | hardcoded | enabled:true, allowed_actions:all |
/contents/{path} (GET) | contents/{path} file | 404 (new file) |
secret list | hardcoded | empty |
variable list | hardcoded | [] |
repo edit, write APIs | no-op | success with delay |
All mock responses include a random 200-500ms delay to simulate network latency.
Check resource headroom: Adding a tape increases parallel resource demand. Count existing tapes (ls docs/tapes/*.tape | wc -l) and multiply by per-container memory (--memory in vhs.sh). If the total approaches or exceeds Docker Desktop's memory allocation, warn the user to either increase Docker Desktop memory (recommended: 16 GB) or consider reducing per-container resources. See the vhs-demo skill for details.
Create the tape: docs/tapes/demo-<name>.tape
Output demo-<name>.gif and Output demo-<name>.mp4Create the setup script: docs/tapes/setup-<name>.sh
chmod +x$MOCK_DIR with the GitHub state the demo needs/tmp/demo/Update Makefile: Add the new GIF to the cp line in the demo target:
@cp docs/tapes/demo-<name>.gif docs/public/ 2>/dev/null || true
Test locally: Run make demo or test the single tape:
docker run --rm -v docs/tapes:/data -w /data gh-infra-vhs demo-<name>.tape
Verify output: Check that both .mp4 and .gif are non-zero size
Hide/Show block is critical. Viewers should never see the setup phase.mock-gh with a new pattern-match block.Type speed is global (TypingSpeed 50ms). For dramatic pauses, use Sleep between Type and Enter.