Real-time asciinema recording backup to GitHub orphan branch with idle-based chunking and brotli archival. TRIGGERS - streaming backup, recording backup, asciinema backup, continuous recording, session backup, orphan branch recording, zstd streaming, chunked recording, real-time backup, github recording storage.
/plugin marketplace add terrylica/cc-skills/plugin install asciinema-tools@cc-skillsThis skill is limited to using the following tools:
references/autonomous-validation.mdreferences/github-workflow.mdreferences/idle-chunker.mdreferences/setup-scripts.mdComplete system for streaming asciinema recordings to GitHub with automatic brotli archival. Uses idle-detection for intelligent chunking, zstd for concatenatable streaming compression, and GitHub Actions for final brotli recompression.
Platform: macOS, Linux Isolation: Uses Git orphan branch (separate history, cannot pollute main)
┌─────────────────┐ zstd chunks ┌─────────────────┐ Actions ┌─────────────────┐
│ asciinema rec │ ──────────────────▶ │ GitHub Orphan │ ───────────────▶ │ brotli archive │
│ + idle-chunker │ (concatenatable) │ gh-recordings │ │ (300x compress)│
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
│ Idle ≥30s triggers chunk │ Separate history
▼ │ Cannot PR to main
~/asciinema_recordings/ ▼
└── repo-name/ .github/workflows/
└── chunks/*.zst └── recompress.yml
| Component | Required | Installation | Version |
|---|---|---|---|
| asciinema CLI | Yes | brew install asciinema | 3.0+ (Rust) |
| zstd | Yes | brew install zstd | Any |
| brotli | Yes | brew install brotli | Any |
| git | Yes | Pre-installed | 2.20+ |
| gh CLI | Yes | brew install gh | Any |
| fswatch | Optional | brew install fswatch | For real-time |
Purpose: Verify all tools installed, offer self-correction if missing.
/usr/bin/env bash << 'PREFLIGHT_EOF'
# preflight-check.sh - Validates all requirements
MISSING=()
# Check each tool
for tool in asciinema zstd brotli git gh; do
if ! command -v "$tool" &>/dev/null; then
MISSING+=("$tool")
fi
done
if [[ ${#MISSING[@]} -gt 0 ]]; then
echo "Missing tools: ${MISSING[*]}"
echo ""
echo "Install with:"
echo " brew install ${MISSING[*]}"
exit 1
fi
# Check asciinema version (need 3.0+ for Rust version)
ASCIINEMA_VERSION=$(asciinema --version 2>&1 | grep -oE '[0-9]+\.[0-9]+' | head -1)
if [[ "${ASCIINEMA_VERSION%%.*}" -lt 3 ]]; then
echo "Warning: asciinema $ASCIINEMA_VERSION detected. Version 3.0+ recommended."
echo "Upgrade: brew upgrade asciinema"
fi
echo "All requirements satisfied"
PREFLIGHT_EOF
AskUserQuestion (if tools missing):
AskUserQuestion:
question: "Required tools are missing. How would you like to proceed?"
header: "Preflight Check"
options:
- label: "Install all missing tools (Recommended)"
description: "Run: brew install ${MISSING[*]}"
- label: "Show manual installation commands"
description: "Display commands without executing"
- label: "Continue anyway (may fail later)"
description: "Skip installation and proceed"
Self-Correction: If tools are missing, generate installation command and offer to run it.
Purpose: Detect available GitHub accounts and let user choose which to use for recording storage.
Probe these 5 sources to detect GitHub accounts:
| Source | Command | What it finds |
|---|---|---|
| SSH config | grep -A5 "Host github" ~/.ssh/config | Match directives with IdentityFile |
| SSH keys | ls ~/.ssh/id_ed25519_* | Account-named keys (e.g., id_ed25519_terrylica) |
| gh CLI | gh auth status | Authenticated accounts |
| mise env | grep GH_ACCOUNT .mise.toml | GH_ACCOUNT variable |
| git config | git config user.name | Global git username |
/usr/bin/env bash << 'DETECT_ACCOUNTS_EOF'
# detect-github-accounts.sh - Probe all sources for GitHub accounts
# Uses portable parallel arrays (works in bash 3.2+ and when wrapped for zsh)
ACCOUNT_NAMES=()
ACCOUNT_SOURCES=()
log() { echo "[detect] $*"; }
# Helper: add account with source (updates existing or appends new)
add_account() {
local account="$1" source="$2"
local idx
for idx in "${!ACCOUNT_NAMES[@]}"; do
if [[ "${ACCOUNT_NAMES[$idx]}" == "$account" ]]; then
ACCOUNT_SOURCES[$idx]+="$source "
return
fi
done
ACCOUNT_NAMES+=("$account")
ACCOUNT_SOURCES+=("$source ")
}
# 1. SSH config Match directives
if [[ -f ~/.ssh/config ]]; then
while IFS= read -r line; do
if [[ "$line" =~ IdentityFile.*id_ed25519_([a-zA-Z0-9_-]+) ]]; then
add_account "${BASH_REMATCH[1]}" "ssh-config"
fi
done < ~/.ssh/config
fi
# 2. SSH key filenames
for keyfile in ~/.ssh/id_ed25519_*; do
if [[ -f "$keyfile" && "$keyfile" != *.pub ]]; then
account=$(basename "$keyfile" | sed 's/id_ed25519_//')
add_account "$account" "ssh-key"
fi
done
# 3. gh CLI authenticated accounts
if command -v gh &>/dev/null; then
while IFS= read -r account; do
[[ -n "$account" ]] && add_account "$account" "gh-cli"
done < <(gh auth status 2>&1 | grep -oE 'Logged in to github.com account [a-zA-Z0-9_-]+' | awk '{print $NF}')
fi
# 4. mise env GH_ACCOUNT
if [[ -f .mise.toml ]]; then
account=$(grep -E 'GH_ACCOUNT\s*=' .mise.toml 2>/dev/null | sed 's/.*=\s*"\([^"]*\)".*/\1/')
[[ -n "$account" ]] && add_account "$account" "mise-env"
fi
# 5. git config user.name
git_user=$(git config user.name 2>/dev/null)
[[ -n "$git_user" ]] && add_account "$git_user" "git-config"
# Score and display
log "=== Detected GitHub Accounts ==="
RECOMMENDED=""
MAX_SOURCES=0
for idx in "${!ACCOUNT_NAMES[@]}"; do
account="${ACCOUNT_NAMES[$idx]}"
sources="${ACCOUNT_SOURCES[$idx]}"
count=$(echo "$sources" | wc -w | tr -d ' ')
log "$account: $count sources ($sources)"
if (( count > MAX_SOURCES )); then
MAX_SOURCES=$count
RECOMMENDED="$account"
RECOMMENDED_SOURCES="$sources"
fi
done
echo ""
echo "RECOMMENDED=$RECOMMENDED"
echo "SOURCES=$RECOMMENDED_SOURCES"
DETECT_ACCOUNTS_EOF
AskUserQuestion:
question: "Which GitHub account should be used for recording storage?"
header: "GitHub Account Selection"
options:
- label: "${RECOMMENDED} (Recommended)"
description: "Detected via: ${SOURCES}"
# Additional detected accounts appear here dynamically
- label: "Enter manually"
description: "Type a GitHub username not listed above"
Post-Selection: If user selects an account, ensure gh CLI is using that account:
/usr/bin/env bash << 'POST_SELECT_EOF'
# Ensure gh CLI is authenticated as selected account
SELECTED_ACCOUNT="${1:?Usage: provide selected account}"
if ! gh auth status 2>&1 | grep -q "Logged in to github.com account $SELECTED_ACCOUNT"; then
echo "Switching gh CLI to account: $SELECTED_ACCOUNT"
gh auth switch --user "$SELECTED_ACCOUNT" 2>/dev/null || \
echo "Warning: Could not switch accounts. Manual auth may be needed."
fi
POST_SELECT_EOF
Purpose: Detect current git repository context to provide intelligent defaults for Phase 2 questions.
/usr/bin/env bash << 'DETECT_REPO_EOF'
# Detect current repository context for intelligent defaults
CURRENT_REPO_URL=""
CURRENT_REPO_OWNER=""
CURRENT_REPO_NAME=""
DETECTED_FROM=""
# Check if we're in a git repository
if git rev-parse --git-dir &>/dev/null; then
# Try origin remote first
if git remote get-url origin &>/dev/null; then
CURRENT_REPO_URL=$(git remote get-url origin)
DETECTED_FROM="origin remote"
# Fallback to first available remote
elif [[ -n "$(git remote)" ]]; then
REMOTE=$(git remote | head -1)
CURRENT_REPO_URL=$(git remote get-url "$REMOTE")
DETECTED_FROM="$REMOTE remote"
fi
# Parse owner and name from URL (SSH or HTTPS)
if [[ -n "$CURRENT_REPO_URL" ]]; then
if [[ "$CURRENT_REPO_URL" =~ github\.com[:/]([^/]+)/([^/.]+) ]]; then
CURRENT_REPO_OWNER="${BASH_REMATCH[1]}"
CURRENT_REPO_NAME="${BASH_REMATCH[2]%.git}"
fi
fi
fi
# Output for Claude to parse
echo "CURRENT_REPO_URL=$CURRENT_REPO_URL"
echo "CURRENT_REPO_OWNER=$CURRENT_REPO_OWNER"
echo "CURRENT_REPO_NAME=$CURRENT_REPO_NAME"
echo "DETECTED_FROM=$DETECTED_FROM"
DETECT_REPO_EOF
Claude Action: Store detected values (CURRENT_REPO_OWNER, CURRENT_REPO_NAME, DETECTED_FROM) for use in subsequent AskUserQuestion calls. If no repo detected, proceed without defaults.
Purpose: Gather essential configuration from user.
If current repo detected (from Phase 1.5):
AskUserQuestion:
question: "Which repository should store the recordings?"
header: "Repository"
options:
- label: "${CURRENT_REPO_OWNER}/${CURRENT_REPO_NAME} (Recommended)"
description: "Current repo detected from ${DETECTED_FROM}"
- label: "Create dedicated repo: ${GITHUB_ACCOUNT}/asciinema-recordings"
description: "Separate repository for all recordings"
- label: "Enter different repository"
description: "Specify another repository (user/repo format)"
If no current repo detected:
AskUserQuestion:
question: "Enter the GitHub repository URL for storing recordings:"
header: "Repository URL"
options:
- label: "Create dedicated repo: ${GITHUB_ACCOUNT}/asciinema-recordings"
description: "Separate repository for all recordings (Recommended)"
- label: "Enter repository manually"
description: "SSH (git@github.com:user/repo.git), HTTPS, or shorthand (user/repo)"
URL Normalization (handles multiple formats):
/usr/bin/env bash << 'NORMALIZE_URL_EOF'
# Normalize to SSH format for consistent handling
normalize_repo_url() {
local url="$1"
# Shorthand: user/repo -> git@github.com:user/repo.git
if [[ "$url" =~ ^[a-zA-Z0-9_-]+/[a-zA-Z0-9_.-]+$ ]]; then
echo "git@github.com:${url}.git"
# HTTPS: https://github.com/user/repo -> git@github.com:user/repo.git
elif [[ "$url" =~ ^https://github\.com/([^/]+)/([^/]+)/?$ ]]; then
echo "git@github.com:${BASH_REMATCH[1]}/${BASH_REMATCH[2]%.git}.git"
# Already SSH format
else
echo "$url"
fi
}
URL="${1:?Usage: provide URL to normalize}"
normalize_repo_url "$URL"
NORMALIZE_URL_EOF
Confirmation for free-form input (if user selected "Enter different/manually"):
AskUserQuestion:
question: "You entered '${USER_INPUT}'. Normalized to: ${NORMALIZED_URL}. Is this correct?"
header: "Confirm Repository"
options:
- label: "Yes, use ${NORMALIZED_URL}"
description: "Proceed with this repository"
- label: "No, let me re-enter"
description: "Go back to repository selection"
AskUserQuestion:
question: "Where should recordings be stored locally?"
header: "Recording Directory"
options:
- label: "~/asciinema_recordings/${RESOLVED_REPO_NAME} (Recommended)"
description: "Example: ~/asciinema_recordings/alpha-forge"
- label: "Custom path"
description: "Enter a different directory path"
Note: ${RESOLVED_REPO_NAME} is the actual repo name from Phase 1.5 or Phase 2.1, not a variable placeholder. Display the concrete path to user.
AskUserQuestion:
question: "What should the orphan branch be named?"
header: "Branch Name"
options:
- label: "asciinema-recordings (Recommended)"
description: "Matches ~/asciinema_recordings/ parent directory pattern"
- label: "gh-recordings"
description: "GitHub-prefixed alternative (gh = GitHub storage)"
- label: "recordings"
description: "Minimal name"
- label: "Custom"
description: "Enter a custom branch name"
Naming Convention: The default asciinema-recordings matches the parent directory ~/asciinema_recordings/ for consistency.
Purpose: Allow customization of compression and behavior parameters.
| Parameter | Default | Options |
|---|---|---|
| Idle threshold | 30s | 15s, 30s (Recommended), 60s, Custom (5-300) |
| zstd level | 3 | 1 (fast), 3 (Recommended), 6, Custom (1-22) |
| Brotli level | 9 | 6, 9 (Recommended), 11, Custom (1-11) |
| Auto-push | Yes | Yes (Recommended), No |
| Poll interval | 5s | 2s, 5s (Recommended), 10s |
3.1 Idle Threshold:
AskUserQuestion:
question: "How long should the chunker wait before creating a chunk?"
header: "Idle Threshold"
options:
- label: "15 seconds"
description: "More frequent chunks, smaller files"
- label: "30 seconds (Recommended)"
description: "Balanced chunk size and frequency"
- label: "60 seconds"
description: "Larger chunks, less frequent uploads"
- label: "Custom (5-300 seconds)"
description: "Enter a custom threshold"
3.2 zstd Compression Level:
AskUserQuestion:
question: "What zstd compression level for streaming chunks?"
header: "zstd Level"
options:
- label: "1 (Fast)"
description: "Fastest compression, larger files"
- label: "3 (Recommended)"
description: "Good balance of speed and compression"
- label: "6 (Better compression)"
description: "Slower but smaller chunks"
- label: "Custom (1-22)"
description: "Enter a custom level"
3.3 Brotli Compression Level:
AskUserQuestion:
question: "What brotli compression level for final archives?"
header: "Brotli Level"
options:
- label: "6"
description: "Faster archival, slightly larger files"
- label: "9 (Recommended)"
description: "Great compression with reasonable speed"
- label: "11 (Maximum)"
description: "Best compression, slowest (may timeout on large files)"
- label: "Custom (1-11)"
description: "Enter a custom level"
3.4 Auto-Push:
AskUserQuestion:
question: "Should chunks be automatically pushed to GitHub?"
header: "Auto-Push"
options:
- label: "Yes (Recommended)"
description: "Push immediately after each chunk"
- label: "No"
description: "Manual push when ready"
3.5 Poll Interval:
AskUserQuestion:
question: "How often should the chunker check for idle state?"
header: "Poll Interval"
options:
- label: "2 seconds"
description: "More responsive, slightly higher CPU"
- label: "5 seconds (Recommended)"
description: "Good balance"
- label: "10 seconds"
description: "Lower resource usage"
Purpose: Create or configure the orphan branch with GitHub Actions workflow.
/usr/bin/env bash << 'CHECK_BRANCH_EOF'
# Check if branch exists on remote
REPO_URL="${1:?Usage: provide repo URL}"
BRANCH="${2:-asciinema-recordings}" # From Phase 2 (default changed)
if git ls-remote --heads "$REPO_URL" "$BRANCH" 2>/dev/null | grep -q "$BRANCH"; then
echo "Branch '$BRANCH' already exists on remote"
echo "BRANCH_EXISTS=true"
else
echo "Branch '$BRANCH' does not exist"
echo "BRANCH_EXISTS=false"
fi
CHECK_BRANCH_EOF
AskUserQuestion:
question: "Branch '${BRANCH}' already exists on remote. How should we proceed?"
header: "Existing Branch"
options:
- label: "Clone locally (Recommended)"
description: "Use existing branch, clone to local directory"
- label: "Reset and recreate fresh"
description: "Delete remote branch and start over (DESTRUCTIVE)"
- label: "Keep existing and verify"
description: "Check existing setup matches configuration"
- label: "Show manual instructions"
description: "Display commands without executing"
/usr/bin/env bash << 'SETUP_ORPHAN_EOF'
# setup-orphan-branch.sh - Creates asciinema-recordings orphan branch
REPO_URL="${1:?Usage: setup-orphan-branch.sh <repo_url> [branch] [local_dir] [brotli_level]}"
BRANCH="${2:-asciinema-recordings}" # Default changed to match parent dir pattern
LOCAL_DIR="${3:-$HOME/asciinema_recordings/$(basename "$REPO_URL" .git)}"
BROTLI_LEVEL="${4:-9}" # Embedded from Phase 3 selection
# Create temporary clone for setup
TEMP_DIR=$(mktemp -d)
trap "rm -rf $TEMP_DIR" EXIT
git clone --depth 1 "$REPO_URL" "$TEMP_DIR"
cd "$TEMP_DIR"
# Create orphan branch
git checkout --orphan "$BRANCH"
git rm -rf .
# Setup directory structure
mkdir -p .github/workflows chunks archives
# Create workflow with user-selected brotli level (EMBEDDED at creation time)
cat > .github/workflows/recompress.yml << WORKFLOW_EOF
name: Recompress to Brotli
on:
push:
branches: [$BRANCH]
paths: ['chunks/**/*.zst']
workflow_dispatch:
jobs:
recompress:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Install compression tools
run: sudo apt-get update && sudo apt-get install -y zstd brotli
- name: Recompress chunks to brotli
run: |
if compgen -G "chunks/*.zst" > /dev/null; then
mkdir -p archives
ARCHIVE_NAME="archive_\$(date +%Y%m%d_%H%M%S).cast.br"
ls -1 chunks/*.zst | sort | xargs cat | zstd -d | brotli -${BROTLI_LEVEL} -o "archives/\$ARCHIVE_NAME"
rm -f chunks/*.zst
echo "Created: archives/\$ARCHIVE_NAME"
echo "ARCHIVE_NAME=\$ARCHIVE_NAME" >> \$GITHUB_ENV
else
echo "No chunks to process"
fi
- name: Commit archive
if: env.ARCHIVE_NAME != ''
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "chore: archive recording to brotli (\${{ env.ARCHIVE_NAME }})"
file_pattern: 'archives/*.br chunks/'
WORKFLOW_EOF
# Create placeholder files
echo '# Recording chunks (zstd compressed)' > chunks/README.md
echo '# Brotli archives (final compressed)' > archives/README.md
# Create README
cat > README.md << 'README_EOF'
# Recording Storage (Orphan Branch)
This branch stores asciinema recording backups. It is completely isolated from the main codebase.
## Structure
- `chunks/` - Streaming zstd-compressed chunks (auto-deleted after archival)
- `archives/` - Final brotli-compressed recordings (~300x compression)
## How It Works
1. Local idle-chunker monitors asciinema recording
2. When idle ≥30s, creates zstd chunk and pushes here
3. GitHub Action concatenates chunks and recompresses to brotli
4. Chunks are deleted, archive is retained
## Isolation Guarantee
This is an orphan branch with no shared history with main.
Git refuses to merge: "refusing to merge unrelated histories"
README_EOF
# Commit and push
git add .
git commit -m "init: recording storage (orphan branch)"
git push -u origin "$BRANCH"
cd -
# Clone to local recordings directory
mkdir -p "$(dirname "$LOCAL_DIR")"
git clone --single-branch --branch "$BRANCH" --depth 1 "$REPO_URL" "$LOCAL_DIR"
echo "Setup complete: $LOCAL_DIR"
SETUP_ORPHAN_EOF
Purpose: Configure local directory and generate chunker script with user parameters.
/usr/bin/env bash << 'SETUP_LOCAL_EOF'
REPO_NAME="${1:?Usage: provide repo name}"
REPO_URL="${2:?Usage: provide repo URL}"
BRANCH="${3:-asciinema-recordings}"
LOCAL_DIR="$HOME/asciinema_recordings/${REPO_NAME}"
# Ensure directories exist
mkdir -p "$LOCAL_DIR/chunks"
mkdir -p "$LOCAL_DIR/archives"
# Clone if not present
if [[ ! -d "$LOCAL_DIR/.git" ]]; then
git clone --single-branch --branch "$BRANCH" --depth 1 "$REPO_URL" "$LOCAL_DIR"
fi
echo "LOCAL_DIR=$LOCAL_DIR"
SETUP_LOCAL_EOF
Generate the chunker script with user-selected parameters embedded:
/usr/bin/env bash << 'GEN_CHUNKER_EOF'
# Parameters from Phase 3 (passed as arguments)
LOCAL_DIR="${1:?Usage: provide LOCAL_DIR}"
IDLE_THRESHOLD="${2:-30}"
ZSTD_LEVEL="${3:-3}"
POLL_INTERVAL="${4:-5}"
PUSH_ENABLED="${5:-true}"
cat > "$LOCAL_DIR/idle-chunker.sh" << CHUNKER_EOF
#!/usr/bin/env bash
# idle-chunker.sh - Generated with user configuration
#
# Configuration (embedded from setup):
# IDLE_THRESHOLD=${IDLE_THRESHOLD}
# ZSTD_LEVEL=${ZSTD_LEVEL}
# POLL_INTERVAL=${POLL_INTERVAL}
# PUSH_ENABLED=${PUSH_ENABLED}
set -euo pipefail
CAST_FILE="\${1:?Usage: idle-chunker.sh <cast_file>}"
# Embedded configuration
IDLE_THRESHOLD=${IDLE_THRESHOLD}
ZSTD_LEVEL=${ZSTD_LEVEL}
POLL_INTERVAL=${POLL_INTERVAL}
PUSH_ENABLED=${PUSH_ENABLED}
cd "\$(dirname "\$0")"
last_pos=0
echo "Monitoring: \$CAST_FILE"
echo "Idle threshold: \${IDLE_THRESHOLD}s | zstd level: \${ZSTD_LEVEL} | Poll: \${POLL_INTERVAL}s"
while [[ -f "\$CAST_FILE" ]] || sleep 2; do
[[ -f "\$CAST_FILE" ]] || continue
mtime=\$(stat -f%m "\$CAST_FILE" 2>/dev/null || stat -c%Y "\$CAST_FILE")
idle=\$((\$(date +%s) - mtime))
size=\$(stat -f%z "\$CAST_FILE" 2>/dev/null || stat -c%s "\$CAST_FILE")
if (( idle >= IDLE_THRESHOLD && size > last_pos )); then
chunk="chunks/chunk_\$(date +%Y%m%d_%H%M%S).cast"
tail -c +\$((last_pos + 1)) "\$CAST_FILE" > "\$chunk"
zstd -\${ZSTD_LEVEL} --rm "\$chunk"
if [[ "\$PUSH_ENABLED" == "true" ]]; then
git add chunks/ && git commit -m "chunk \$(date +%H:%M)" && git push
fi
last_pos=\$size
echo "[\$(date +%H:%M:%S)] Created: \${chunk}.zst"
fi
sleep \$POLL_INTERVAL
done
CHUNKER_EOF
chmod +x "$LOCAL_DIR/idle-chunker.sh"
echo "Generated: $LOCAL_DIR/idle-chunker.sh"
GEN_CHUNKER_EOF
/usr/bin/env bash << 'SETUP_EOF'
echo ""
echo "=== Setup Complete ==="
echo ""
echo "Configuration:"
echo " Repository: $REPO_URL"
echo " Branch: $BRANCH"
echo " Local directory: $LOCAL_DIR"
echo ""
echo "Parameters:"
echo " Idle threshold: ${IDLE_THRESHOLD}s"
echo " zstd level: $ZSTD_LEVEL"
echo " Brotli level: $BROTLI_LEVEL"
echo " Auto-push: $PUSH_ENABLED"
echo " Poll interval: ${POLL_INTERVAL}s"
echo ""
echo "To start recording:"
echo " 1. asciinema rec /path/to/session.cast"
echo " 2. $LOCAL_DIR/idle-chunker.sh /path/to/session.cast"
SETUP_EOF
Purpose: Claude executes validation tests automatically, displaying results in CLI. Only interrupts user when human action is required.
| Test | Autonomous? | Reason |
|---|---|---|
| 1. Tool preflight | ✅ YES | Bash checks tools |
| 2. zstd round-trip | ✅ YES | Synthetic test data |
| 3. Brotli round-trip | ✅ YES | Synthetic test data |
| 4. zstd concatenation | ✅ YES | Critical for streaming |
| 5. Git/gh auth check | ✅ YES | Query auth status |
| 6. Orphan branch validation | ✅ YES | Check remote/local |
| 7. Workflow file check | ✅ YES | Read file contents |
| 8. GitHub Actions trigger | ✅ YES | gh workflow run + watch |
| 9. Recording test | ❌ USER | Requires starting asciinema |
| 10. Chunker live test | ❌ USER | Requires active recording |
Claude runs the validation script and displays formatted results:
╔════════════════════════════════════════════════════════════════╗
║ AUTONOMOUS VALIDATION - Claude Code Executes All Tests ║
╠════════════════════════════════════════════════════════════════╣
║ ║
║ Phase 1: Tool Check ║
║ ───────────────── ║
║ [RUN] Checking asciinema... ✓ installed (v3.0.0) ║
║ [RUN] Checking zstd... ✓ installed (v1.5.5) ║
║ [RUN] Checking brotli... ✓ installed (v1.1.0) ║
║ [RUN] Checking git... ✓ installed (v2.43.0) ║
║ [RUN] Checking gh... ✓ installed (v2.40.0) ║
║ ║
║ Phase 2: Compression Tests ║
║ ──────────────────────── ║
║ [RUN] zstd round-trip... ✓ PASSED ║
║ [RUN] brotli round-trip... ✓ PASSED ║
║ [RUN] zstd concatenation... ✓ PASSED (critical for streaming) ║
║ ║
║ Phase 3: Repository Validation ║
║ ───────────────────────────── ║
║ [RUN] Checking gh auth... ✓ authenticated as terrylica ║
║ [RUN] Checking orphan branch... ✓ gh-recordings exists ║
║ [RUN] Checking local clone... ✓ ~/asciinema_recordings/repo ║
║ [RUN] Checking workflow file... ✓ recompress.yml present ║
║ ║
║ Phase 4: GitHub Actions Test ║
║ ───────────────────────────── ║
║ [RUN] Triggering workflow_dispatch... ✓ triggered ║
║ [RUN] Watching run #12345... ⏳ in_progress ║
║ [RUN] Watching run #12345... ✓ completed (success) ║
║ ║
║ ═══════════════════════════════════════════════════════════ ║
║ AUTONOMOUS TESTS: 8/8 PASSED ║
║ ═══════════════════════════════════════════════════════════ ║
╚════════════════════════════════════════════════════════════════╝
Only TWO tests require user action:
Test 9: Recording Validation
AskUserQuestion:
question: "Ready to test recording? This requires you to start asciinema in another terminal."
header: "Recording Test"
options:
- label: "Guide me through it (Recommended)"
description: "Step-by-step instructions"
- label: "Skip this test"
description: "I'll verify manually later"
- label: "I've already verified recording works"
description: "Mark as passed"
If "Guide me through it" selected, display:
╔════════════════════════════════════════════════════════════════╗
║ USER ACTION REQUIRED: Recording Test ║
╠════════════════════════════════════════════════════════════════╣
║ ║
║ In a NEW terminal, run: ║
║ ┌────────────────────────────────────────────────────────┐ ║
║ │ asciinema rec ~/asciinema_recordings/test_session.cast │ ║
║ └────────────────────────────────────────────────────────┘ ║
║ ║
║ Then type a few commands and exit with Ctrl+D ║
║ ║
║ Come back here when done. ║
╚════════════════════════════════════════════════════════════════╝
Then Claude autonomously validates the created file:
# Claude runs after user confirms:
[RUN] Checking test_session.cast exists... ✓
[RUN] Validating JSON header... ✓ {"version": 2, ...}
[RUN] Checking line count... ✓ 23 events recorded
Test 10: Chunker Live Test
AskUserQuestion:
question: "Ready to test live chunking? This requires running recording + chunker simultaneously."
header: "Chunker Test"
options:
- label: "Guide me (Recommended)"
description: "Two-terminal workflow instructions"
- label: "Skip - I trust the setup"
description: "Skip live test"
See references/autonomous-validation.md for the complete validation script.
If any test fails, Claude displays inline troubleshooting:
[RUN] Checking gh auth... ✗ FAILED
Troubleshooting:
1. Run: gh auth login
2. Select: GitHub.com
3. Choose: HTTPS or SSH
4. Follow prompts to authenticate
Then re-run validation.
/usr/bin/env bash << 'PREFLIGHT_EOF'
# 1. Check requirements
for tool in asciinema zstd brotli git gh; do
command -v "$tool" &>/dev/null && echo "$tool: OK" || echo "$tool: MISSING"
done
# 2. Create orphan branch (replace with your repo)
REPO="git@github.com:YOUR/REPO.git"
./setup-orphan-branch.sh "$REPO"
# 3. Validate setup
./validate-setup.sh "$HOME/asciinema_recordings/REPO"
PREFLIGHT_EOF
/usr/bin/env bash << 'SKILL_SCRIPT_EOF'
# Terminal 1: Start recording
WORKSPACE=$(basename "$PWD")
asciinema rec $PWD/tmp/${WORKSPACE}_$(date +%Y-%m-%d_%H-%M).cast
# Terminal 2: Start idle-chunker
~/asciinema_recordings/REPO/idle-chunker.sh $PWD/tmp/${WORKSPACE}_*.cast
SKILL_SCRIPT_EOF
1. [Preflight] Validate all tools installed (asciinema, zstd, brotli, git, gh)
2. [Preflight] AskUserQuestion: offer installation for missing tools
3. [Account] Detect GitHub accounts from 5 sources
4. [Account] AskUserQuestion: select GitHub account
5. [Config] AskUserQuestion: repository URL
6. [Config] AskUserQuestion: recording directory
7. [Config] AskUserQuestion: branch name
8. [Advanced] AskUserQuestion: idle threshold
9. [Advanced] AskUserQuestion: zstd level
10. [Advanced] AskUserQuestion: brotli level
11. [Advanced] AskUserQuestion: auto-push
12. [Advanced] AskUserQuestion: poll interval
13. [Branch] Check if orphan branch exists on remote
14. [Branch] AskUserQuestion: handle existing branch
15. [Branch] Create orphan branch if needed
16. [Branch] Create GitHub Actions workflow with embedded parameters
17. [Local] Clone orphan branch to ~/asciinema_recordings/
18. [Local] Generate idle-chunker.sh with embedded parameters
19. [Validate] Run autonomous validation (8 tests)
20. [Validate] AskUserQuestion: recording test (user action)
21. [Validate] AskUserQuestion: chunker live test (user action)
22. [Guide] Display configuration summary and usage instructions
1. [Context] Detect workspace from $PWD
2. [Context] Generate datetime for filename
3. [Context] Ensure tmp/ directory exists
4. [Command] Generate asciinema rec command
5. [Command] Generate idle-chunker command
6. [Guide] Display two-terminal workflow instructions
Cause: Authentication or permissions issue.
Fix:
# Check gh auth status
gh auth status
# Re-authenticate if needed
gh auth login
Cause: Idle threshold not reached, or file not growing.
Fix:
tail -f $CAST_FILEIDLE_THRESHOLD=15Cause: Workflow file missing or wrong branch filter.
Fix:
# Verify workflow exists
cat ~/asciinema_recordings/REPO/.github/workflows/recompress.yml
# Check branch filter includes gh-recordings
grep -A2 "branches:" ~/asciinema_recordings/REPO/.github/workflows/recompress.yml
Cause: zstd chunks not concatenating properly (overlapping data).
Fix: Ensure idle-chunker uses last_chunk_pos to avoid overlap:
/usr/bin/env bash << 'PREFLIGHT_EOF_2'
# Check for overlaps - each chunk should be sequential
for f in chunks/*.zst; do
zstd -d "$f" -c | head -1
done
PREFLIGHT_EOF_2
| Decision | Rationale |
|---|---|
| zstd for streaming | Supports frame concatenation (brotli doesn't) |
| brotli for archival | Best compression ratio (~300x for .cast files) |
| Orphan branch | Complete isolation, can't pollute main history |
| Idle-based chunking | Semantic breakpoints, not mid-output splits |
| Shallow clone | Minimal disk usage, can't accidentally access main |
| 30s idle threshold | Balances chunk frequency vs semantic completeness |
After modifying this skill:
This skill should be used when the user asks about libraries, frameworks, API references, or needs code examples. Activates for setup questions, code generation involving libraries, or mentions of specific frameworks like React, Vue, Next.js, Prisma, Supabase, etc.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.