asciinema-converter ยท diff
git:20260131.1a586f8 to git:20260226.c78f2f5
25 added, 435 removed. Audit A to A.
---
name: asciinema-converter
description: Convert .cast recordings to .txt for analysis. TRIGGERS - convert cast, cast to txt, strip ANSI, batch convert.
allowed-tools: Read, Bash, Glob, Write, AskUserQuestion
---
# asciinema-converter
Convert asciinema .cast recordings to clean .txt files for Claude Code analysis. Achieves 950:1 compression (3.8GB -> 4MB) by stripping ANSI codes and JSON structure.
> **Platform**: macOS, Linux (requires asciinema CLI v2.4+)
## When to Use This Skill
Use this skill when:
- Converting .cast recordings to searchable .txt format
- Preparing recordings for Claude Code Read/Grep tools
- Batch converting multiple recordings
- Reducing storage size of session archives
- Extracting clean text from ANSI-coded terminal output
---
## Why Convert?
| Format | Size (22h session) | Claude Code Compatible | Searchable |
| ------ | ------------------ | ---------------------- | ---------- |
| .cast | 3.8GB | No (NDJSON + ANSI) | Via jq |
| .txt | ~4MB | Yes (clean text) | Grep/Read |
**Key benefit**: Claude Code's Read and Grep tools work directly on .txt output.
---
## Requirements
| Component | Required | Installation | Notes |
| ------------- | -------- | ------------------------ | --------------------- |
| **asciinema** | Yes | `brew install asciinema` | v2.4+ for convert cmd |
---
- ## Workflow Phases (ALL MANDATORY)
+ ## Workflow Overview
**IMPORTANT**: All phases are MANDATORY. Do NOT skip any phase. AskUserQuestion MUST be used at each decision point.
- ### Phase 0: Preflight Check
-
- **Purpose**: Verify asciinema is installed and supports convert command.
-
- ```bash
- /usr/bin/env bash << 'PREFLIGHT_EOF'
- if command -v asciinema &>/dev/null; then
- VERSION=$(asciinema --version | head -1)
- echo "asciinema: $VERSION"
-
- # Check if convert command exists (v2.4+)
- if asciinema convert --help &>/dev/null 2>&1; then
- echo "convert: available"
- else
- echo "convert: MISSING (update asciinema to v2.4+)"
- fi
- else
- echo "asciinema: MISSING"
- fi
- PREFLIGHT_EOF
- ```
-
- If asciinema is NOT installed or convert is missing, use AskUserQuestion:
-
- ```
- Question: "asciinema CLI issue detected. How would you like to proceed?"
- Header: "Setup"
- Options:
- - Label: "Install/upgrade asciinema (Recommended)"
- Description: "Run: brew install asciinema (or upgrade if outdated)"
- - Label: "Show manual instructions"
- Description: "Display installation commands for all platforms"
- - Label: "Cancel"
- Description: "Exit without converting"
- ```
-
- ---
-
- ### Phase 1: File Discovery & Selection (MANDATORY)
-
- **Purpose**: Discover .cast files and let user select which to convert.
-
- #### Step 1.1: Discover .cast Files
-
- ```bash
- /usr/bin/env bash << 'DISCOVER_EOF'
- # Search for .cast files with metadata
- for file in $(fd -e cast . --max-depth 5 2>/dev/null | head -10); do
- SIZE=$(ls -lh "$file" 2>/dev/null | awk '{print $5}')
- LINES=$(wc -l < "$file" 2>/dev/null | tr -d ' ')
- DURATION=$(head -1 "$file" 2>/dev/null | jq -r '.duration // "unknown"' 2>/dev/null)
- BASENAME=$(basename "$file")
- echo "FILE:$file|SIZE:$SIZE|LINES:$LINES|DURATION:$DURATION|NAME:$BASENAME"
- done
- DISCOVER_EOF
- ```
-
- #### Step 1.2: Present File Selection (MANDATORY AskUserQuestion)
-
- Use discovery results to populate options:
-
- ```
- Question: "Which recording would you like to convert?"
- Header: "Recording"
- Options:
- - Label: "{filename} ({size})"
- Description: "{line_count} events, {duration}s duration"
- - Label: "{filename2} ({size2})"
- Description: "{line_count2} events, {duration2}s duration"
- - Label: "Browse for file"
- Description: "Search in a different directory"
- - Label: "Enter path"
- Description: "Provide a custom path to a .cast file"
- ```
-
- ---
-
- ### Phase 2: Output Options (MANDATORY)
-
- **Purpose**: Let user configure conversion behavior.
-
- ```
- Question: "Select conversion options:"
- Header: "Options"
- multiSelect: true
- Options:
- - Label: "Plain text output (Recommended)"
- Description: "Convert to .txt with all ANSI codes stripped"
- - Label: "Create timestamp index"
- Description: "Generate [HH:MM:SS] indexed version for navigation"
- - Label: "Split by idle time"
- Description: "Create separate chunks at 30s+ pauses"
- - Label: "Preserve terminal dimensions"
- Description: "Add header with original terminal size"
- ```
-
- ---
-
- ### Phase 3: Output Location (MANDATORY)
-
- **Purpose**: Let user choose where to save the output.
-
- ```
- Question: "Where should the output be saved?"
- Header: "Output"
- Options:
- - Label: "Same directory as source (Recommended)"
- Description: "Save {filename}.txt next to {filename}.cast"
- - Label: "Workspace tmp/"
- Description: "Save to ${PWD}/tmp/"
- - Label: "Custom path"
- Description: "Specify a custom output location"
- ```
-
- ---
-
- ### Phase 4: Execute Conversion
-
- **Purpose**: Run the conversion and report results.
-
- #### Step 4.1: Run asciinema convert
-
- ```bash
- /usr/bin/env bash << 'CONVERT_EOF'
- INPUT_FILE="${1:?Input file required}"
- OUTPUT_FILE="${2:?Output file required}"
-
- echo "Converting: $INPUT_FILE"
- echo "Output: $OUTPUT_FILE"
- echo ""
-
- # Run conversion
- asciinema convert -f txt "$INPUT_FILE" "$OUTPUT_FILE"
-
- if [[ $? -eq 0 && -f "$OUTPUT_FILE" ]]; then
- echo "Conversion successful"
- else
- echo "ERROR: Conversion failed"
- exit 1
- fi
- CONVERT_EOF
- ```
-
- #### Step 4.2: Report Compression
-
- ```bash
- /usr/bin/env bash << 'REPORT_EOF'
- INPUT_FILE="${1:?}"
- OUTPUT_FILE="${2:?}"
-
- # Get file sizes (macOS compatible)
- INPUT_SIZE=$(stat -f%z "$INPUT_FILE" 2>/dev/null || stat -c%s "$INPUT_FILE" 2>/dev/null)
- OUTPUT_SIZE=$(stat -f%z "$OUTPUT_FILE" 2>/dev/null || stat -c%s "$OUTPUT_FILE" 2>/dev/null)
-
- # Calculate ratio
- if [[ $OUTPUT_SIZE -gt 0 ]]; then
- RATIO=$((INPUT_SIZE / OUTPUT_SIZE))
- else
- RATIO=0
- fi
-
- # Human-readable sizes
- INPUT_HR=$(numfmt --to=iec "$INPUT_SIZE" 2>/dev/null || echo "$INPUT_SIZE bytes")
- OUTPUT_HR=$(numfmt --to=iec "$OUTPUT_SIZE" 2>/dev/null || echo "$OUTPUT_SIZE bytes")
-
- echo ""
- echo "=== Conversion Complete ==="
- echo "Input: $INPUT_HR"
- echo "Output: $OUTPUT_HR"
- echo "Compression: ${RATIO}:1"
- echo "Output path: $OUTPUT_FILE"
- REPORT_EOF
- ```
-
- ---
-
- ### Phase 5: Create Timestamp Index (if selected)
-
- **Purpose**: Generate indexed version for navigation.
-
- ```bash
- /usr/bin/env bash << 'INDEX_EOF'
- INPUT_CAST="${1:?}"
- OUTPUT_INDEX="${2:?}"
-
- echo "Creating timestamp index..."
-
- # Process .cast file to indexed format
- (
- echo "# Recording Index"
- echo "# Format: [HH:MM:SS] content"
- echo "#"
-
- cumtime=0
- tail -n +2 "$INPUT_CAST" | while IFS= read -r line; do
- # Extract timestamp and content
- ts=$(echo "$line" | jq -r '.[0]' 2>/dev/null)
- type=$(echo "$line" | jq -r '.[1]' 2>/dev/null)
- content=$(echo "$line" | jq -r '.[2]' 2>/dev/null)
-
- if [[ "$type" == "o" && -n "$content" ]]; then
- # Format timestamp as HH:MM:SS
- hours=$((${ts%.*} / 3600))
- mins=$(((${ts%.*} % 3600) / 60))
- secs=$((${ts%.*} % 60))
- timestamp=$(printf "%02d:%02d:%02d" "$hours" "$mins" "$secs")
-
- # Clean and output (strip ANSI, limit length)
- clean=$(echo "$content" | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' | tr -d '\r' | head -c 200)
- [[ -n "$clean" ]] && echo "[$timestamp] $clean"
- fi
- done
- ) > "$OUTPUT_INDEX"
-
- echo "Index created: $OUTPUT_INDEX"
- wc -l "$OUTPUT_INDEX"
- INDEX_EOF
- ```
-
- ---
-
- ### Phase 6: Next Steps (MANDATORY)
-
- **Purpose**: Guide user to next action.
-
- ```
- Question: "Conversion complete. What's next?"
- Header: "Next"
- Options:
- - Label: "Analyze with /asciinema-tools:analyze"
- Description: "Run keyword extraction on the converted file"
- - Label: "Open in editor"
- Description: "View the converted text file"
- - Label: "Done"
- Description: "Exit - no further action needed"
- ```
-
- ---
-
- ## Batch Mode (Phases 7-9)
-
- Batch mode converts all .cast files in a directory with organized output. Activated via `--batch` flag.
-
- **Use case**: Convert 1000+ iTerm2 auto-logged recordings efficiently.
-
- ### Phase 7: Batch Source Selection
-
- **Purpose**: Select source directory for batch conversion.
-
- **Trigger**: `--batch` flag without `--source` argument.
-
- ```
- Question: "Select source directory for batch conversion:"
- Header: "Source"
- Options:
- - Label: "~/asciinemalogs (iTerm2 default)" (Recommended)
- Description: "Auto-logged iTerm2 recordings"
- - Label: "~/Downloads"
- Description: "Recent downloads containing .cast files"
- - Label: "Current directory"
- Description: "Convert .cast files in current working directory"
- - Label: "Custom path"
- Description: "Specify a custom source directory"
- ```
-
- **Skip condition**: If `--source` argument provided, skip this phase.
-
- ---
-
- ### Phase 8: Batch Output Organization
-
- **Purpose**: Configure output directory structure.
-
- **Trigger**: `--batch` flag without `--output-dir` argument.
-
- ```
- Question: "Where should converted files be saved?"
- Header: "Output"
- Options:
- - Label: "~/Downloads/cast-txt/ (Recommended)"
- Description: "Organized output directory, easy to find"
- - Label: "Same as source"
- Description: "Save .txt files next to .cast files"
- - Label: "Custom directory"
- Description: "Specify a custom output location"
- ```
-
- **Skip condition**: If `--output-dir` argument provided, skip this phase.
-
- ---
-
- ### Phase 9: Execute Batch Conversion
-
- **Purpose**: Convert all files with progress reporting.
-
- ```bash
- /usr/bin/env bash << 'BATCH_EOF'
- SOURCE_DIR="${1:?Source directory required}"
- OUTPUT_DIR="${2:?Output directory required}"
- SKIP_EXISTING="${3:-true}"
-
- mkdir -p "$OUTPUT_DIR"
-
- echo "=== Batch Conversion ==="
- echo "Source: $SOURCE_DIR"
- echo "Output: $OUTPUT_DIR"
- echo "Skip existing: $SKIP_EXISTING"
- echo ""
-
- total=0
- converted=0
- skipped=0
- failed=0
- total_input_size=0
- total_output_size=0
-
- # Count files first
- total=$(find "$SOURCE_DIR" -maxdepth 1 -name "*.cast" -type f 2>/dev/null | wc -l | tr -d ' ')
- echo "Found $total .cast files"
- echo ""
-
- for cast_file in "$SOURCE_DIR"/*.cast; do
- [[ -f "$cast_file" ]] || continue
-
- basename=$(basename "$cast_file" .cast)
- txt_file="$OUTPUT_DIR/${basename}.txt"
-
- # Skip if already converted (and skip mode enabled)
- if [[ "$SKIP_EXISTING" == "true" && -f "$txt_file" ]]; then
- echo "SKIP: $basename (already exists)"
- ((skipped++))
- continue
- fi
-
- # Get input size
- input_size=$(stat -f%z "$cast_file" 2>/dev/null || stat -c%s "$cast_file" 2>/dev/null)
-
- # Convert
- if asciinema convert -f txt "$cast_file" "$txt_file" 2>/dev/null; then
- output_size=$(stat -f%z "$txt_file" 2>/dev/null || stat -c%s "$txt_file" 2>/dev/null)
- if [[ $output_size -gt 0 ]]; then
- ratio=$((input_size / output_size))
- else
- ratio=0
- fi
- echo "OK: $basename (${ratio}:1 compression)"
- ((converted++))
- total_input_size=$((total_input_size + input_size))
- total_output_size=$((total_output_size + output_size))
- else
- echo "FAIL: $basename"
- ((failed++))
- fi
- done
+ ### Single File Mode (Phases 0-6)
- echo ""
- echo "=== Batch Complete ==="
- echo "Converted: $converted"
- echo "Skipped: $skipped"
- echo "Failed: $failed"
+ | Phase | Purpose | Key Action |
+ | ----- | -------------------------- | --------------------------------- |
+ | 0 | Preflight check | Verify asciinema CLI v2.4+ |
+ | 1 | File discovery & selection | AskUserQuestion: file to convert |
+ | 2 | Output options | AskUserQuestion: conversion opts |
+ | 3 | Output location | AskUserQuestion: save destination |
+ | 4 | Execute conversion | `asciinema convert -f txt` |
+ | 5 | Timestamp index | Optional `[HH:MM:SS]` index |
+ | 6 | Next steps | AskUserQuestion: what's next |
- if [[ $total_output_size -gt 0 ]]; then
- overall_ratio=$((total_input_size / total_output_size))
- echo "Overall compression: ${overall_ratio}:1"
- fi
- echo "Output directory: $OUTPUT_DIR"
- BATCH_EOF
- ```
+ Full implementation details: [Workflow Phases](./references/workflow-phases.md)
- ---
+ ### Batch Mode (Phases 7-10)
- ### Phase 10: Batch Next Steps
+ Activated via `--batch` flag. Converts all .cast files in a directory with organized output.
- **Purpose**: Guide user after batch conversion.
+ | Phase | Purpose | Key Action |
+ | ----- | ------------------- | ---------------------------------------- |
+ | 7 | Source selection | AskUserQuestion (skip if `--source`) |
+ | 8 | Output organization | AskUserQuestion (skip if `--output-dir`) |
+ | 9 | Execute batch | Convert all with progress reporting |
+ | 10 | Batch next steps | AskUserQuestion: what's next |
- ```
- Question: "Batch conversion complete. What's next?"
- Header: "Next"
- Options:
- - Label: "Batch analyze with /asciinema-tools:analyze --batch"
- Description: "Run keyword extraction on all converted files"
- - Label: "Open output directory"
- Description: "View converted files in Finder"
- - Label: "Done"
- Description: "Exit - no further action needed"
- ```
+ Full implementation details: [Batch Workflow](./references/batch-workflow.md)
---
## iTerm2 Filename Format
iTerm2 auto-logged files follow this format:
```
{creationTimeString}.{profileName}.{termid}.{iterm2.pid}.{autoLogId}.cast
```
**Example**: `20260118_232025.Claude Code.w0t1p1.70C05103-2F29-4B42-8067-BE475DB6126A.68721.4013739999.cast`
| Component | Description | Example |
| ------------------ | ------------------------------ | ------------------------------------ |
| creationTimeString | YYYYMMDD_HHMMSS | 20260118_232025 |
| profileName | iTerm2 profile (may have dots) | Claude Code |
| termid | Window/tab/pane identifier | w0t1p1 |
| iterm2.pid | iTerm2 process UUID | 70C05103-2F29-4B42-8067-BE475DB6126A |
| autoLogId | Session auto-log identifier | 68721.4013739999 |
---
- ## TodoWrite Task Template
-
- ### Single File Mode
-
- ```
- 1. [Preflight] Check asciinema CLI and convert command
- 2. [Preflight] Offer installation if missing
- 3. [Discovery] Find .cast files with metadata
- 4. [Selection] AskUserQuestion: file to convert
- 5. [Options] AskUserQuestion: conversion options (multi-select)
- 6. [Location] AskUserQuestion: output location
- 7. [Convert] Run asciinema convert -f txt
- 8. [Report] Display compression ratio and output path
- 9. [Index] Create timestamp index if requested
- 10. [Next] AskUserQuestion: next steps
- ```
-
- ### Batch Mode (--batch flag)
-
- ```
- 1. [Preflight] Check asciinema CLI and convert command
- 2. [Preflight] Offer installation if missing
- 3. [Source] AskUserQuestion: source directory (skip if --source)
- 4. [Output] AskUserQuestion: output directory (skip if --output-dir)
- 5. [Batch] Execute batch conversion with progress
- 6. [Report] Display aggregate compression stats
- 7. [Next] AskUserQuestion: batch next steps
- ```
-
- ---
-
- ## Post-Change Checklist
-
- After modifying this skill:
-
- ### Single File Mode
-
- 1. [ ] Preflight check detects asciinema version correctly
- 2. [ ] Discovery uses heredoc wrapper for bash compatibility
- 3. [ ] Compression calculation handles macOS stat syntax
- 4. [ ] All AskUserQuestion phases are present
- 5. [ ] TodoWrite template matches actual workflow
-
- ### Batch Mode
-
- 1. [ ] `--batch` flag triggers batch workflow (phases 7-10)
- 2. [ ] `--source` skips Phase 7 (source selection)
- 3. [ ] `--output-dir` skips Phase 8 (output organization)
- 4. [ ] `--skip-existing` prevents re-conversion of existing files
- 5. [ ] Aggregate compression ratio calculated correctly
- 6. [ ] iTerm2 filename format documented
-
- ---
-
## CLI Quick Reference
```bash
# Basic conversion
asciinema convert -f txt recording.cast recording.txt
# Check asciinema version
asciinema --version
# Verify convert command exists
asciinema convert --help
```
---
## Reference Documentation
### Internal References
+ - [Workflow Phases](./references/workflow-phases.md) - Single file mode phases 0-6 with full scripts
+ - [Batch Workflow](./references/batch-workflow.md) - Batch mode phases 7-10 with full scripts
+ - [Task Templates](./references/task-templates.md) - TodoWrite templates for single and batch modes
+ - [Post-Change Checklist](./references/post-change-checklist.md) - Verification after modifications
- [Anti-Patterns](./references/anti-patterns.md) - Common mistakes to avoid
- [Batch Processing](./references/batch-processing.md) - Patterns for bulk conversion
- [Integration Guide](./references/integration-guide.md) - Chaining with analyze/summarize
### External References
- [asciinema convert command](https://docs.asciinema.org/manual/cli/)
- [asciinema-cast-format skill](../asciinema-cast-format/SKILL.md)
---
## Troubleshooting
| Issue | Cause | Solution |
| --------------------------- | ------------------------- | ---------------------------------------------- |
| convert command not found | asciinema too old | Upgrade: `brew upgrade asciinema` (need v2.4+) |
| asciinema not installed | Missing CLI | `brew install asciinema` |
| Empty output file | Corrupted .cast input | Verify .cast file has valid NDJSON structure |
| Conversion failed | Invalid cast format | Check header line is valid JSON with `jq` |
| numfmt not found | macOS missing coreutils | Use raw byte count or `brew install coreutils` |
| stat syntax error | Linux vs macOS difference | Script handles both; check stat version |
| Batch skipping all files | All .txt already exist | Use `--skip-existing=false` to reconvert |
| Permission denied on output | Directory not writable | Check output directory permissions |