Skip to content
Back to skills

Feature Video

ASecurity

This skill should be used to record video walkthroughs of features for PR descriptions. Captures browser interactions via agent-browser CLI; optional GIF/MP4 via ffmpeg and upload via rclone.

  • 16 stars
  • 0 votes
  • 2 copies
  • 3 views
  • Added May 27, 2026
data-aijavascriptpythonjavabashrailsgitapidocumentation

Works with

  • claude code
  • cli
  • api

Security analysis

A93/100
  • highPerforms destructive filesystem operations

Pro scans all 2 files and shows the line behind each finding

Scanned September 25, 2026

npx -y skills add jikig-ai/soleur --skill feature-video --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Feature Video?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Feature Video
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jikig-ai-feature-video/badge)](https://www.skillsdirectory.com/skills/jikig-ai-feature-video)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: feature-video
description: "This skill should be used to record video walkthroughs of features for PR descriptions. Captures browser interactions via agent-browser CLI; optional GIF/MP4 via ffmpeg and upload via rclone."
---

<!-- grok-harness-invoke:start -->
**Grok Build (`plugins/soleur/lib/harness.ts` `invokeSkill()`):** Read this SKILL.md in this process and run it to completion. A one-segment `soleur:<name>` in this document names a SKILL — on Grok Build, Read `plugins/soleur/skills/<name>/SKILL.md` in this process; it is not a nested tool_use. A multi-segment id such as `soleur:<domain>:<name>` names an AGENT: spawn it, never Read it, and on Grok Build spawn_subagent takes the id with its colons replaced by hyphens (`agentIdToGrokSubagentType`). **Claude Code:** Skill tool for a skill (`soleur:<name>`), Task tool with `subagent_type` for an agent. Forbidden is executing a subset, not the Read.
<!-- grok-harness-invoke:end -->

# Feature Video Walkthrough

<command_purpose>Record a video walkthrough demonstrating a feature, upload it, and add it to the PR description.</command_purpose>

## Introduction

<role>Developer Relations Engineer creating feature demo videos</role>

This skill creates professional video walkthroughs of features for PR documentation:

- Records browser interactions using agent-browser CLI
- Demonstrates the complete user flow
- Converts screenshots to video/GIF (when ffmpeg is available)
- Uploads to cloud storage (when rclone is configured)
- Updates the PR description with the best available output

## Prerequisites

<requirements>
- Local development server running (e.g., `bin/dev`, `rails server`)
- agent-browser CLI installed (required)
- Git repository with a PR to document
- `ffmpeg` installed (optional -- without it, screenshots are captured but no video/GIF is created). Can be installed automatically by the dependency check script.
- `rclone` configured (optional -- without it, video stays local instead of uploading to cloud storage). Can be installed automatically by the dependency check script.
</requirements>

## Phase 0: Dependency Check

Run [check_deps.sh](./scripts/check_deps.sh) before proceeding. When invoked from a pipeline (e.g., one-shot), pass `--auto` to skip interactive prompts and install missing tools automatically:

```bash
bash "${CLAUDE_PLUGIN_ROOT}/skills/feature-video/scripts/check_deps.sh"
```

For pipeline/automated use:

```bash
bash "${CLAUDE_PLUGIN_ROOT}/skills/feature-video/scripts/check_deps.sh" --auto
```

If the script exits non-zero, agent-browser is missing and recording cannot proceed. Stop and inform the user.

If ffmpeg or rclone show `[skip]`, note which tools are unavailable. The skill continues with degraded capability:

- **No ffmpeg**: Capture screenshots only. Skip video/GIF creation in steps 4-5.
- **No rclone**: Create video locally. Skip upload in step 6.

Store the availability as variables for use in later steps:

```bash
HAS_FFMPEG=$(command -v ffmpeg >/dev/null 2>&1 && echo "true" || echo "false")
HAS_RCLONE=$(command -v rclone >/dev/null 2>&1 && echo "true" || echo "false")
RCLONE_CONFIGURED="false"
if [ "$HAS_RCLONE" = "true" ]; then
  REMOTES=$(rclone listremotes 2>/dev/null || true)
  [ -n "$REMOTES" ] && RCLONE_CONFIGURED="true"
fi
```

## Main Tasks

### 1. Parse Arguments

<parse_args>

**Arguments:** $ARGUMENTS

Parse the input:

- First argument: PR number or "current" (defaults to current branch's PR)
- Second argument: Base URL (defaults to `http://localhost:3000`)

```bash
# Get PR number for current branch if needed
gh pr view --json number -q '.number'
```

</parse_args>

### 2. Gather Feature Context

<gather_context>

**Get PR details:**

```bash
gh pr view [number] --json title,body,files,headRefName -q '.'
```

**Get changed files:**

```bash
gh pr view [number] --json files -q '.files[].path'
```

**Map files to testable routes** (same as playwright-test):

| File Pattern | Route(s) |
|-------------|----------|
| `app/views/users/*` | `/users`, `/users/:id`, `/users/new` |
| `app/controllers/settings_controller.rb` | `/settings` |
| `app/javascript/controllers/*_controller.js` | Pages using that Stimulus controller |
| `app/components/*_component.rb` | Pages rendering that component |

</gather_context>

### 3. Plan the Video Flow

<plan_flow>

Before recording, create a shot list:

1. **Opening shot**: Homepage or starting point (2-3 seconds)
2. **Navigation**: How user gets to the feature
3. **Feature demonstration**: Core functionality (main focus)
4. **Edge cases**: Error states, validation, etc. (if applicable)
5. **Success state**: Completed action/result

Ask user to confirm or adjust the flow:

```markdown
**Proposed Video Flow**

Based on PR #[number]: [title]

1. Start at: /[starting-route]
2. Navigate to: /[feature-route]
3. Demonstrate:
   - [Action 1]
   - [Action 2]
   - [Action 3]
4. Show result: [success state]

Estimated duration: ~[X] seconds

Does this look right?
1. Yes, start recording
2. Modify the flow (describe changes)
3. Add specific interactions to demonstrate
```

</plan_flow>

### 4. Setup Video Recording

<setup_recording>

**Create directories:**

```bash
mkdir -p tmp/screenshots tmp/videos
```

**Recording approach: Use browser screenshots as frames**

agent-browser captures screenshots at key moments. If ffmpeg is available, screenshots are combined into video/GIF in step 5.

**If ffmpeg is unavailable:** Screenshots are the final output. Skip video/GIF creation commands in step 5.

</setup_recording>

### 5. Record the Walkthrough

<record_walkthrough>

Execute the planned flow, capturing each step:

**Step 1: Navigate to starting point**

On Linux (Ubuntu 23.10+, containers, VMs), export the no-sandbox launch flag once
before the first command — otherwise Chrome cannot launch and `open` hangs (see the
`agent-browser` skill's "Chrome fails to launch / `open` hangs" troubleshooting):

```bash
export AGENT_BROWSER_ARGS="--no-sandbox"
agent-browser open "[base-url]/[start-route]"
agent-browser wait 2000
agent-browser screenshot tmp/screenshots/01-start.png
```

**Step 2: Perform navigation/interactions**

### Preflight: verify the plugin install before any snapshot

The redactor is reached through `${CLAUDE_PLUGIN_ROOT}`. An ambient value pointing at a
directory that is not a Soleur install would resolve to a path that does not exist — or, worse,
to one an attacker chose. Verify plugin IDENTITY and halt if it does not hold (ADR-179 decision 2);
a `test -f` on the script alone is a shape check and was measured bypassable.

```bash
[ -f "${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json" ] \
  && grep -q '"name"[[:space:]]*:[[:space:]]*"soleur"' "${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json" \
  || { echo "SOLEUR_SNAPSHOT_HALT reason=plugin-root-unverified root=[${CLAUDE_PLUGIN_ROOT}]" >&2
       echo "  Cannot locate the snapshot redactor, so no accessibility snapshot may be taken here." >&2
       echo "  Root EMPTY: no Soleur plugin is loaded in this session. Install it and start a NEW session." >&2
       echo "  Root set but wrong: a repo checkout is not an install. Run 'claude plugin update soleur@soleur-marketplace' (or the id 'claude plugin list' prints, if you added the repository directly), then RESTART Claude Code." >&2
       echo "  Nothing has been captured yet, so nothing has leaked." >&2
       exit 2; }
```

```bash
agent-browser snapshot -i 2>&1 | python3 "${CLAUDE_PLUGIN_ROOT}/skills/agent-browser/scripts/redact-a11y-snapshot.py"  # Get refs
agent-browser click @e1    # Click navigation element
agent-browser wait 1000
agent-browser screenshot tmp/screenshots/02-navigate.png
```

**Step 3: Demonstrate feature**

```bash
agent-browser snapshot -i 2>&1 | python3 "${CLAUDE_PLUGIN_ROOT}/skills/agent-browser/scripts/redact-a11y-snapshot.py"  # Get refs for feature elements
agent-browser click @e2    # Click feature element
agent-browser wait 1000
agent-browser screenshot tmp/screenshots/03-feature.png
```

**Step 4: Capture result**

```bash
agent-browser wait 2000
agent-browser screenshot tmp/screenshots/04-result.png
```

**Create video/GIF from screenshots (skip if ffmpeg unavailable):**

If `HAS_FFMPEG=false`, skip the ffmpeg commands below. The screenshots in `tmp/screenshots/` are the final output. Inform the user: "ffmpeg not installed -- screenshots captured but video/GIF creation skipped."

```bash
# Only run if HAS_FFMPEG=true

# Create MP4 video (RECOMMENDED - better quality, smaller size)
# -framerate 0.5 = 2 seconds per frame (slower playback)
# -framerate 1 = 1 second per frame
ffmpeg -y -framerate 0.5 -pattern_type glob -i 'tmp/screenshots/*.png' \
  -c:v libx264 -pix_fmt yuv420p -vf "scale=1280:-2" \
  tmp/videos/feature-demo.mp4

# Create low-quality GIF for preview (small file, for GitHub embed)
ffmpeg -y -framerate 0.5 -pattern_type glob -i 'tmp/screenshots/*.png' \
  -vf "scale=640:-1:flags=lanczos,split[s0][s1];[s0]palettegen=max_colors=128[p];[s1][p]paletteuse" \
  -loop 0 tmp/videos/feature-demo-preview.gif
```

**Note:**

- The `-2` in MP4 scale ensures height is divisible by 2 (required for H.264)
- Preview GIF uses 640px width and 128 colors to keep file size small (~100-200KB)

</record_walkthrough>

### 6. Upload the Video

<upload_video>

**Skip this step if `RCLONE_CONFIGURED=false`.** Inform the user: "rclone not available or not configured -- video retained locally at tmp/videos/."

**Upload with rclone (only if RCLONE_CONFIGURED=true):**

```bash
# Upload video, preview GIF, and screenshots to cloud storage
# Use --s3-no-check-bucket to avoid permission errors
rclone copy tmp/videos/ r2:kieran-claude/pr-videos/pr-[number]/ --s3-no-check-bucket --progress
rclone copy tmp/screenshots/ r2:kieran-claude/pr-videos/pr-[number]/screenshots/ --s3-no-check-bucket --progress

# List uploaded files
rclone ls r2:kieran-claude/pr-videos/pr-[number]/
```

Public URLs (R2 with public access):

```
Video: https://pub-4047722ebb1b4b09853f24d3b61467f1.r2.dev/pr-videos/pr-[number]/feature-demo.mp4
Preview: https://pub-4047722ebb1b4b09853f24d3b61467f1.r2.dev/pr-videos/pr-[number]/feature-demo-preview.gif
```

</upload_video>

### 7. Update PR Description

<update_pr>

**Get current PR body:**

```bash
gh pr view [number] --json body -q '.body'
```

**Add a demo section to the PR description based on what was produced:**

If the PR already has a demo section, replace it. Otherwise, append.

**Case A: Video uploaded (HAS_FFMPEG=true, RCLONE_CONFIGURED=true)**

Use a clickable GIF that links to the video (GitHub cannot embed external MP4s directly):

```markdown
## Demo

[![Feature Demo]([preview-gif-url])]([video-mp4-url])

*Click to view full video*
```

**Case B: Video created locally (HAS_FFMPEG=true, RCLONE_CONFIGURED=false)**

Upload the video to the PR as a GitHub comment attachment before cleanup deletes local files:

```bash
# Upload video as a PR comment (GitHub accepts drag-and-drop or API upload)
echo "Upload tmp/videos/feature-demo.mp4 to PR #[number] as a comment attachment"
```

Then add to PR body:

```markdown
## Demo

See video in PR comments below.
```

**Case C: Screenshots only (HAS_FFMPEG=false)**

Upload screenshots to the PR as comment attachments before cleanup deletes local files, then embed in the PR body:

```markdown
## Demo

Screenshots captured (video conversion requires ffmpeg). See PR comments for images.
```

**Update the PR:**

```bash
gh pr edit [number] --body "[updated body with demo section]"
```

</update_pr>

### 8. Cleanup

<cleanup>

```bash
# Always clean up tmp artifacts after PR description is updated
rm -rf tmp/screenshots tmp/videos
echo "Cleaned up tmp/screenshots/ and tmp/videos/"
```

</cleanup>

### 9. Summary

<summary>

Present completion summary:

```markdown
## Feature Video Complete

**PR:** #[number] - [title]
**Video:** [url or local path]
**Duration:** ~[X] seconds
**Format:** [GIF/MP4]

### Shots Captured
1. [Starting point] - [description]
2. [Navigation] - [description]
3. [Feature demo] - [description]
4. [Result] - [description]

### PR Updated
- [x] Video section added to PR description
- [ ] Ready for review

**Next steps:**
- Review the video to ensure it accurately demonstrates the feature
- Share with reviewers for context
```

</summary>

## Quick Usage Examples

```bash
# Record video for current branch's PR
soleur:feature-video

# Record video for specific PR
soleur:feature-video 847

# Record with custom base URL
soleur:feature-video 847 http://localhost:5000

# Record for staging environment
soleur:feature-video current https://staging.example.com
```

## Tips

- **Keep it short**: 10-30 seconds is ideal for PR demos
- **Focus on the change**: Don't include unrelated UI
- **Show before/after**: If fixing a bug, show the broken state first (if possible)
- **Annotate if needed**: Add text overlays for complex features

Files in this skill

  • SKILL.md10.2 KB
  • scripts/check_deps.sh8.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.