[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6C2G6XPJB37S775N5QVG6Z1":3,"skill-same:01M6C2G6XPJB37S775N5QVG6Z1":66},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":27,"publishedAt":40,"linkOnly":41,"markdownContent":42,"markdownBody":43,"frontMatter":44,"refName":45,"commitSha":46,"skillDirectory":47,"forksCount":48,"repositoryHtmlUrl":49,"repositoryHomepageUrl":6,"ownerHtmlUrl":50,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":51,"install":52,"resources":65},"01M6C2G6XPJB37S775N5QVG6Z1","ui-video-evidence",null,"Record captioned browser\u002FUI evidence videos and link sanitized artifacts for authorized review","jleechanorg\u002Fjleechan-skills","jleechanorg","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F221404966?v=4","01M6C1VJ99XG950X1DWPEBCBGX","01M6C1VJDK5YVDNT3362RT5WSB",6,"MIT","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fui-video-evidence\u002FSKILL.md",[17,22],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000016","图像与多媒体","SCENARIO","使用场景",{"categoryNo":23,"categoryName":24,"taxonomyType":25,"taxonomyTypeDesc":26},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[28,29,30,31,32,33,34,35,36,37,38,39],"ui","Video","evidence","ui video evidence","review","artifacts","browser","record","link","videos","ui evidence","for","2026-11-10 10:12:30",false,"---\nname: ui-video-evidence\ndescription: Record captioned browser\u002FUI evidence videos and link sanitized artifacts for authorized review\n---\n\n# UI Video Evidence for Visual Verification\n\n## Purpose\n\nProve user-visible behavior in a way reviewers and agents can verify quickly from the PR conversation.\n\nBefore producing or reviewing any video, apply the canonical [`evidence-standards` continuous-video rule](..\u002Fevidence-standards\u002FSKILL.md#continuous-video-only--slideshows-are-forbidden). Screenshot sequences and slideshow MP4s never satisfy video evidence.\n\n## When UI Video Is Required\n\nApply the narrow proportional exceptions in [pr-lifecycle](..\u002Fpr-lifecycle\u002FSKILL.md) first. Source-only harmless display-copy may justify media N\u002FA; a bounded static-copy rendering claim may use an actual screenshot. Other UI\u002Fbrowser video is mandatory for user-facing behavior, including:\n- Visual\u002FUI layout or styling changes\n- Click flows, form submit flows, navigation, or modal behavior\n- New\u002Fchanged browser interactions\n- Any claim of visual correctness or lack of visual regression\n\nOutside those explicit exceptions, missing applicable UI video is an evidence failure. Never waive requested interaction, streaming or native proof by calling it a string change.\n\n## Required Outputs\n\nEach video run must provide the following; the simple-static screenshot exception\nretains the canonical paired-capture, provenance, and visual-review requirements:\n- UI video (`.mp4` preferred)\n- UI fallback media (`.gif` recommended when player embed is not required)\n- Captions (burned-in preferred; `.vtt`\u002F`.srt` acceptable)\n- Git linkage (`git rev-parse HEAD` visible in recording context)\n- Media links accessible to the intended reviewer at an authorized destination\n- A browser-viewable artifact (`.gif`, commit-pinned raw asset, release asset, or native attachment)\n- A downloadable high-fidelity artifact (`.mp4`, `.mp4.zip`, or release asset)\n- Matching metadata and caption artifacts in the reviewed evidence receipt\n\n## Scoped Browser Ownership (resolve FIRST, before picking a capture method)\n\nBefore choosing how to capture evidence, check whether the target repo has its\nown browser-execution owner (e.g. `testing_ui\u002FCLAUDE.md`,\n`..\u002Fbrowser-testing\u002FSKILL.md`). If a scoped owner exists and\nforbids headed\u002Fmanual capture or Claude-in-Chrome, its policy wins — use its\ndesignated headless tool (Aside CLI\u002F`aside-mcp`, or headless Playwright). Do\nnot escalate to a native-chrome\u002Fmanual-capture requirement, and do not ask for\nScreen Recording permission, when a scoped headless path is available and not\ndocumented as blocked.\n\n## Mandatory Frames\n\nCapture this journey on each compared implementation. The pre-action frame below\nis not by itself the pre-change-code baseline; preserve both revisions and their\noriginal capture provenance under the canonical BEFORE\u002FAFTER rule.\n\n| # | Frame | Must show |\n|---|-------|-----------|\n| 1 | URL + Page Load | Full native browser URL bar with route under test, OR — when the scoped owner mandates headless capture — a genuine route\u002FURL provenance marker (printed navigation URL\u002Flog line, on-page route text, or window title) captured from the same automated session and tied to the frame timestamp |\n| 2 | Pre-action State | Initial state before action on this revision |\n| 3 | Action | Click\u002Finput\u002Fnavigation action |\n| 4 | Post-action State | Resulting state after action on this revision |\n| 5 | Git Linkage | Terminal split, devtools log, or on-page SHA marker |\n\n## Recording Options\n\n### Option 1: Scoped headless driver (Aside \u002F Playwright) — DEFAULT\nFollow `..\u002Fbrowser-testing\u002FSKILL.md`: drive the browser headlessly\nvia Aside CLI\u002F`aside-mcp` or headless Playwright, log the navigated URL\u002Froute to\nthe terminal or an overlay, and record with the scoped repo's own recorder\n(e.g. `testing_ui\u002Fstreaming\u002Fbase.py` `UIVideoRecorder`) or `ffmpeg` (Option 3).\nNever use `mcp__claude-in-chrome__*` or any headed browser for this path.\n\n### Option 2: Manual desktop capture (Kap) — LAST RESORT ONLY\nOnly when the current thread explicitly requests visible capture, the browser\nis independently verified as task-owned, and the repo permits it. Absence of a\nrepo prohibition is not authorization. Follow the shared browser-control owner;\nnever use personal\u002Fdefault Chrome, its profiles or its cookies.\n```bash\nbrew install --cask kap\n```\nRecord browser window including address bar.\n\n### Option 3: ffmpeg (headless\u002FCI)\n```bash\nffmpeg -video_size 1280x720 -framerate 10 -f x11grab -i :99 -t 30 \"\u002Ftmp\u002F${WORK_NAME:-work}.mp4\"\n```\n\n## Caption Requirements (MANDATORY)\n\nBoth tmux and UI videos must always have captions.\n\nAccepted forms:\n1. Burned-in captions in the video (preferred)\n2. Sidecar caption file (`.vtt`\u002F`.srt`) linked alongside the reviewed media artifacts\n\nUse `..\u002Fvideo-caption\u002FSKILL.md` for reliable burned-in captions.\n\n## Evidence access and authorized publication\n\nFollow `..\u002Fevidence-standards\u002FSKILL.md` for publication authority, audience, and destination. A PR, checked-in document, access-controlled receipt\u002Fstore, or authorized gist may link the evidence. For PRs governed by pr-lifecycle, its review receipts belong in the PR description; opted-in repositories also link every stage-exit receipt through its required sanitized gist URL (except a pr-lifecycle one-liner fast-path receipt, which lives in the PR body). Applicable inline viewable media and original media URLs are required there. Other authorized artifact storage does not remove that description\u002Fpublication requirement. Preserve real media, captions, exact source provenance, and reviewer access; publish only within the current authorization.\n\nThe following GitHub release example applies only when that destination is authorized. Verify the intended PR exists via `gh pr view` before creating any release or upload. Caller must provide non-empty `VIDEO_FILE` and `PREVIEW_FILE` artifacts, an explicit non-empty `RUN_ID`, an explicit non-empty `CAPTURED_SHA` matching the PR head SHA, and declare an explicit caption choice: set `CAPTION_FILE` to the actual .vtt or .srt sidecar path, or set `CAPTION_MODE=burned` when captions are burned into the video. All media and subtitle formats are verified with ffprobe prior to archive creation and publication. Packaging creates a new archive in a private temporary directory so existing user archives are never overwritten or updated with stale entries. Each run publishes to an immutable unique release tag combining the PR number, commit SHA, and run identifier without overwriting or clobbering existing releases.\n\nThis example publishes a current-candidate capture only. Retain baseline media at\nits actual source SHA through an authorized artifact route; never relabel it as\nthe PR head to satisfy this example's head-equality guard.\n\n```bash\n(\n  set -euo pipefail\n  repo=\"${REPO:-}\"\n  url_regex='^https:\u002F\u002Fgithub\\.com\u002F([^\u002F]+\u002F[^\u002F]+)\u002Fpull\u002F([1-9][0-9]*)\u002F?$'\n\n  if [[ -n \"${PR_NUMBER_OR_URL:-}\" ]]; then\n    if [[ \"$PR_NUMBER_OR_URL\" =~ $url_regex ]]; then\n      url_repo=\"${BASH_REMATCH[1]}\"\n      url_pr=\"${BASH_REMATCH[2]}\"\n      if [[ -n \"$repo\" && \"$repo\" != \"$url_repo\" ]]; then\n        echo \"Error: Conflicting repository target '$repo' vs PR URL '$url_repo'\" >&2\n        exit 1\n      fi\n      repo=\"${repo:-$url_repo}\"\n      if [[ -n \"${PR_NUMBER:-}\" && \"${PR_NUMBER}\" != \"$url_pr\" ]]; then\n        echo \"Error: Conflicting PR number '${PR_NUMBER}' vs PR URL '$url_pr'\" >&2\n        exit 1\n      fi\n      PR_NUMBER=\"$url_pr\"\n    elif [[ \"$PR_NUMBER_OR_URL\" =~ ^[1-9][0-9]*$ ]]; then\n      if [[ -n \"${PR_NUMBER:-}\" && \"${PR_NUMBER}\" != \"$PR_NUMBER_OR_URL\" ]]; then\n        echo \"Error: Conflicting PR number '${PR_NUMBER}' vs PR_NUMBER_OR_URL '$PR_NUMBER_OR_URL'\" >&2\n        exit 1\n      fi\n      PR_NUMBER=\"${PR_NUMBER:-$PR_NUMBER_OR_URL}\"\n    else\n      echo \"Error: PR_NUMBER_OR_URL must be a valid GitHub PR URL or positive PR number\" >&2\n      exit 1\n    fi\n  fi\n\n  if [[ -n \"${PR_NUMBER:-}\" && \"$PR_NUMBER\" =~ $url_regex ]]; then\n    url_repo=\"${BASH_REMATCH[1]}\"\n    url_pr=\"${BASH_REMATCH[2]}\"\n    if [[ -n \"$repo\" && \"$repo\" != \"$url_repo\" ]]; then\n      echo \"Error: Conflicting repository target '$repo' vs PR URL '$url_repo'\" >&2\n      exit 1\n    fi\n    repo=\"${repo:-$url_repo}\"\n    PR_NUMBER=\"$url_pr\"\n  fi\n\n  if ! command -v ffprobe >\u002Fdev\u002Fnull 2>&1; then\n    echo \"Error: ffprobe is required for media validation but not found in PATH\" >&2\n    exit 1\n  fi\n\n  if [[ -z \"${PR_NUMBER:-}\" || \"$PR_NUMBER\" == *\"\u003C\"* || ! \"$PR_NUMBER\" =~ ^[1-9][0-9]*$ ]]; then\n    echo \"Error: PR_NUMBER must be set to a valid PR number before publication\" >&2\n    exit 1\n  fi\n  if [[ -z \"${repo:-}\" || \"$repo\" == *\"\u003C\"* ]]; then\n    echo \"Error: REPO must be set to a valid owner\u002Frepo before publication\" >&2\n    exit 1\n  fi\n  if [[ ! \"$repo\" =~ ^[a-zA-Z0-9_.-]+\u002F[a-zA-Z0-9_.-]+$ ]]; then\n    echo \"Error: REPO must be in the format 'owner\u002Frepo'\" >&2\n    exit 1\n  fi\n  if [[ -z \"${RUN_ID:-}\" || \"$RUN_ID\" == *\"\u003C\"* ]]; then\n    echo \"Error: RUN_ID must be set to an explicit nonempty identifier before publication\" >&2\n    exit 1\n  fi\n  if [[ -z \"${CAPTURED_SHA:-}\" || \"$CAPTURED_SHA\" == *\"\u003C\"* ]]; then\n    echo \"Error: CAPTURED_SHA must be set to the explicit commit SHA captured in the evidence\" >&2\n    exit 1\n  fi\n\n  if [[ -z \"${VIDEO_FILE:-}\" || \"$VIDEO_FILE\" == *\"\u003C\"* ]]; then\n    echo \"Error: VIDEO_FILE must be set to a valid path before publication\" >&2\n    exit 1\n  fi\n  if [[ -z \"${PREVIEW_FILE:-}\" || \"$PREVIEW_FILE\" == *\"\u003C\"* ]]; then\n    echo \"Error: PREVIEW_FILE must be set to a valid path before publication\" >&2\n    exit 1\n  fi\n\n  video_file=\"$VIDEO_FILE\"\n  preview_file=\"$PREVIEW_FILE\"\n\n  if [ ! -f \"$video_file\" ] || [ ! -s \"$video_file\" ]; then\n    echo \"Error: Video file '$video_file' not found or is empty\" >&2\n    exit 1\n  fi\n  if [ ! -f \"$preview_file\" ] || [ ! -s \"$preview_file\" ]; then\n    echo \"Error: Preview file '$preview_file' not found or is empty\" >&2\n    exit 1\n  fi\n\n  video_codec=\"$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_type -of default=noprint_wrappers=1:nokey=1 \"$video_file\" 2>\u002Fdev\u002Fnull || true)\"\n  if [[ \"$video_codec\" != \"video\" ]]; then\n    echo \"Error: Video file '$video_file' does not contain a valid video stream\" >&2\n    exit 1\n  fi\n\n  preview_codec=\"$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_type -of default=noprint_wrappers=1:nokey=1 \"$preview_file\" 2>\u002Fdev\u002Fnull || true)\"\n  if [[ \"$preview_codec\" != \"video\" ]]; then\n    echo \"Error: Preview file '$preview_file' does not contain a valid video\u002Fimage stream\" >&2\n    exit 1\n  fi\n\n  if [[ -n \"${CAPTION_MODE:-}\" && \"${CAPTION_MODE:-}\" != \"burned\" ]]; then\n    echo \"Error: Unsupported CAPTION_MODE '${CAPTION_MODE}': only CAPTION_MODE=burned is supported\" >&2\n    exit 1\n  fi\n\n  if [[ -n \"${CAPTION_FILE:-}\" && \"${CAPTION_MODE:-}\" == \"burned\" ]]; then\n    echo \"Error: Cannot specify both CAPTION_FILE and CAPTION_MODE=burned: choose exactly one caption option\" >&2\n    exit 1\n  fi\n\n  if [[ \"${CAPTION_MODE:-}\" == \"burned\" ]]; then\n    caption_file=\"\"\n  elif [[ -n \"${CAPTION_FILE:-}\" && \"${CAPTION_FILE:-}\" != *\"\u003C\"* ]]; then\n    caption_file=\"$CAPTION_FILE\"\n    if [ ! -f \"$caption_file\" ] || [ ! -s \"$caption_file\" ]; then\n      echo \"Error: Caption sidecar '$caption_file' specified but not found or is empty\" >&2\n      exit 1\n    fi\n    caption_codec=\"$(ffprobe -v error -show_entries stream=codec_type -of default=noprint_wrappers=1:nokey=1 \"$caption_file\" 2>\u002Fdev\u002Fnull || true)\"\n    if [[ \"$caption_codec\" != \"subtitle\" ]]; then\n      echo \"Error: Caption file '$caption_file' does not contain a valid subtitle stream\" >&2\n      exit 1\n    fi\n  else\n    echo \"Error: Explicit caption choice required: specify CAPTION_FILE (.vtt\u002F.srt) or CAPTION_MODE=burned\" >&2\n    exit 1\n  fi\n\n  # Verify exact intended PR before any release creation or mutation\n  pr_view_json=\"$(gh pr view \"$PR_NUMBER\" --repo \"$repo\" --json number,headRefOid,url)\"\n  pr_head_sha=\"$(printf '%s' \"$pr_view_json\" | jq -r '.headRefOid \u002F\u002F empty')\"\n  pr_number_resolved=\"$(printf '%s' \"$pr_view_json\" | jq -r '.number \u002F\u002F empty')\"\n  if [[ -n \"$pr_number_resolved\" && \"$pr_number_resolved\" != \"$PR_NUMBER\" ]]; then\n    echo \"Error: Verified PR number mismatch ($pr_number_resolved vs $PR_NUMBER)\" >&2\n    exit 1\n  fi\n  if [[ -z \"$pr_head_sha\" ]]; then\n    echo \"Error: Unable to resolve head SHA for PR #$PR_NUMBER in $repo\" >&2\n    exit 1\n  fi\n\n  if [[ \"$CAPTURED_SHA\" != \"$pr_head_sha\" ]]; then\n    echo \"Error: Declared CAPTURED_SHA '$CAPTURED_SHA' does not match verified PR head '$pr_head_sha'\" >&2\n    exit 1\n  fi\n\n  sha_short=\"${CAPTURED_SHA:0:12}\"\n  tag=\"evidence-pr-${PR_NUMBER}-${sha_short}-${RUN_ID}\"\n\n  archive_scratch=\"$(\"${CLAUDE_HOME:-$HOME\u002F.claude}\u002Fskills\u002Fscratch-space\u002Fscripts\u002Fscratch-dir.sh\" tmp)\"\n  if [ -z \"$archive_scratch\" ]; then\n    echo \"Scratch resolver returned an empty path; refusing archive allocation\" >&2\n    exit 75\n  fi\n  archive_dir=\"$(mktemp -d \"$archive_scratch\u002Fevidence_archive.XXXXXX\")\"\n  zip_file=\"$archive_dir\u002F$(basename \"$video_file\").zip\"\n  trap 'rm -f -- \"$zip_file\"; rmdir -- \"$archive_dir\"' EXIT\n  zip -j \"$zip_file\" \"$video_file\"\n\n  assets=(\"$zip_file\" \"$preview_file\")\n  if [ -n \"$caption_file\" ]; then\n    assets+=(\"$caption_file\")\n  fi\n\n  if ! gh release create \"$tag\" --repo \"$repo\" --target \"$CAPTURED_SHA\" --draft --title \"PR #${PR_NUMBER} Evidence\" --notes \"\"; then\n    echo \"Error: Release '$tag' could not be created or already exists; stopping without modifying releases\" >&2\n    exit 1\n  fi\n  release_json=\"$(gh release view \"$tag\" --repo \"$repo\" --json assets,targetCommitish,url)\"\n  release_target=\"$(printf '%s' \"$release_json\" | jq -r '.targetCommitish \u002F\u002F empty')\"\n  if [[ -z \"$release_target\" || ! \"$release_target\" =~ ^[0-9a-fA-F]{40}$ ]]; then\n    echo \"Error: Unable to resolve valid target commit for release '$tag' in $repo\" >&2\n    exit 1\n  fi\n  if [[ \"$release_target\" != \"$CAPTURED_SHA\" ]]; then\n    echo \"Error: Verified release target commit '$release_target' does not match CAPTURED_SHA '$CAPTURED_SHA'\" >&2\n    exit 1\n  fi\n  gh release upload \"$tag\" --repo \"$repo\" \"${assets[@]}\"\n  release_json=\"$(gh release view \"$tag\" --repo \"$repo\" --json assets,targetCommitish,url)\"\n  release_target=\"$(printf '%s' \"$release_json\" | jq -r '.targetCommitish \u002F\u002F empty')\"\n  if [[ -z \"$release_target\" || ! \"$release_target\" =~ ^[0-9a-fA-F]{40}$ ]]; then\n    echo \"Error: Unable to resolve valid target commit for release '$tag' in $repo\" >&2\n    exit 1\n  fi\n  if [[ \"$release_target\" != \"$CAPTURED_SHA\" ]]; then\n    echo \"Error: Verified release target commit '$release_target' does not match CAPTURED_SHA '$CAPTURED_SHA'\" >&2\n    exit 1\n  fi\n  for expected_asset in \"${assets[@]}\"; do\n    name=\"$(basename \"$expected_asset\")\"\n    matches=\"$(printf '%s' \"$release_json\" | jq --arg n \"$name\" '[.assets[] | select(.name == $n)]')\"\n    count=\"$(printf '%s' \"$matches\" | jq 'length')\"\n    if [[ \"$count\" -ne 1 ]]; then\n      echo \"Error: Expected asset '$name' present $count time(s) in release readback (must be exactly 1)\" >&2\n      exit 1\n    fi\n    if [[ -z \"$(printf '%s' \"$matches\" | jq -r '.[0].url \u002F\u002F empty')\" ]]; then\n      echo \"Error: Expected asset '$name' has no usable URL in release readback\" >&2\n      exit 1\n    fi\n  done\n  printf '%s\\n' \"$release_json\"\n)\n```\n\nFrom the JSON output returned by `gh release view`, extract the uploaded asset URLs and construct `the canonical Scratch comment body`. Do not guess draft asset download URLs or invent placeholder URLs.\n\nOnce `the canonical Scratch comment body` is constructed, post the comment to the authorized PR:\n\n```bash\n(\n  set -euo pipefail\n  repo=\"${REPO:-}\"\n  url_regex='^https:\u002F\u002Fgithub\\.com\u002F([^\u002F]+\u002F[^\u002F]+)\u002Fpull\u002F([1-9][0-9]*)\u002F?$'\n\n  if [[ -n \"${PR_NUMBER_OR_URL:-}\" ]]; then\n    if [[ \"$PR_NUMBER_OR_URL\" =~ $url_regex ]]; then\n      url_repo=\"${BASH_REMATCH[1]}\"\n      url_pr=\"${BASH_REMATCH[2]}\"\n      if [[ -n \"$repo\" && \"$repo\" != \"$url_repo\" ]]; then\n        echo \"Error: Conflicting repository target '$repo' vs PR URL '$url_repo'\" >&2\n        exit 1\n      fi\n      repo=\"${repo:-$url_repo}\"\n      if [[ -n \"${PR_NUMBER:-}\" && \"${PR_NUMBER}\" != \"$url_pr\" ]]; then\n        echo \"Error: Conflicting PR number '${PR_NUMBER}' vs PR URL '$url_pr'\" >&2\n        exit 1\n      fi\n      PR_NUMBER=\"$url_pr\"\n    elif [[ \"$PR_NUMBER_OR_URL\" =~ ^[1-9][0-9]*$ ]]; then\n      if [[ -n \"${PR_NUMBER:-}\" && \"${PR_NUMBER}\" != \"$PR_NUMBER_OR_URL\" ]]; then\n        echo \"Error: Conflicting PR number '${PR_NUMBER}' vs PR_NUMBER_OR_URL '$PR_NUMBER_OR_URL'\" >&2\n        exit 1\n      fi\n      PR_NUMBER=\"${PR_NUMBER:-$PR_NUMBER_OR_URL}\"\n    else\n      echo \"Error: PR_NUMBER_OR_URL must be a valid GitHub PR URL or positive PR number\" >&2\n      exit 1\n    fi\n  fi\n\n  if [[ -n \"${PR_NUMBER:-}\" && \"$PR_NUMBER\" =~ $url_regex ]]; then\n    url_repo=\"${BASH_REMATCH[1]}\"\n    url_pr=\"${BASH_REMATCH[2]}\"\n    if [[ -n \"$repo\" && \"$repo\" != \"$url_repo\" ]]; then\n      echo \"Error: Conflicting repository target '$repo' vs PR URL '$url_repo'\" >&2\n      exit 1\n    fi\n    repo=\"${repo:-$url_repo}\"\n    PR_NUMBER=\"$url_pr\"\n  fi\n\n  if [[ -z \"${PR_NUMBER:-}\" || \"$PR_NUMBER\" == *\"\u003C\"* || ! \"$PR_NUMBER\" =~ ^[1-9][0-9]*$ ]]; then\n    echo \"Error: PR_NUMBER must be set to a valid PR number before publication\" >&2\n    exit 1\n  fi\n  if [[ -z \"${repo:-}\" || \"$repo\" == *\"\u003C\"* ]]; then\n    echo \"Error: REPO must be set to a valid owner\u002Frepo before publication\" >&2\n    exit 1\n  fi\n  if [[ ! \"$repo\" =~ ^[a-zA-Z0-9_.-]+\u002F[a-zA-Z0-9_.-]+$ ]]; then\n    echo \"Error: REPO must be in the format 'owner\u002Frepo'\" >&2\n    exit 1\n  fi\n  if [[ -z \"${CAPTURED_SHA:-}\" || \"$CAPTURED_SHA\" == *\"\u003C\"* || ! \"$CAPTURED_SHA\" =~ ^[0-9a-fA-F]{40}$ ]]; then\n    echo \"Error: CAPTURED_SHA must be set to a valid 40-character commit SHA\" >&2\n    exit 1\n  fi\n\n  comment_scratch=\"$(\"${CLAUDE_HOME:-$HOME\u002F.claude}\u002Fskills\u002Fscratch-space\u002Fscripts\u002Fscratch-dir.sh\" tmp)\"\n  comment_file=\"${COMMENT_FILE:-$comment_scratch\u002Fevidence_comment.md}\"\n  if [ ! -s \"$comment_file\" ]; then\n    echo \"Error: Comment body file '$comment_file' does not exist or is empty\" >&2\n    exit 1\n  fi\n\n  # Verify exact intended PR before posting comment\n  pr_view_json=\"$(gh pr view \"$PR_NUMBER\" --repo \"$repo\" --json number,headRefOid,url)\"\n  pr_number_resolved=\"$(printf '%s' \"$pr_view_json\" | jq -r '.number \u002F\u002F empty')\"\n  if [[ -n \"$pr_number_resolved\" && \"$pr_number_resolved\" != \"$PR_NUMBER\" ]]; then\n    echo \"Error: Verified PR number mismatch ($pr_number_resolved vs $PR_NUMBER)\" >&2\n    exit 1\n  fi\n  pr_head_sha=\"$(printf '%s' \"$pr_view_json\" | jq -r '.headRefOid \u002F\u002F empty')\"\n  if [[ -z \"$pr_head_sha\" || ! \"$pr_head_sha\" =~ ^[0-9a-fA-F]{40}$ ]]; then\n    echo \"Error: Unable to resolve valid head SHA for PR #$PR_NUMBER in $repo\" >&2\n    exit 1\n  fi\n  if [[ \"$CAPTURED_SHA\" != \"$pr_head_sha\" ]]; then\n    echo \"Error: Declared CAPTURED_SHA '$CAPTURED_SHA' does not match verified PR head '$pr_head_sha'\" >&2\n    exit 1\n  fi\n\n  target_pr=\"$PR_NUMBER\"\n  gh pr comment \"$target_pr\" --repo \"$repo\" --body-file \"$comment_file\"\n)\n```\n\nOptional path:\n- `$HOME\u002F.claude\u002Fscripts\u002Fgithub_pr_media_upload.py` may still be used when native `user-attachments` URLs are specifically desired and a valid GitHub web session cookie is available\n\nBehavior:\n- Keeps publication fully zero-touch via `gh`\n- Produces durable GitHub-hosted URLs that can be pasted into the PR description or comment\n- Avoids dependence on a browser session cookie\n\n## PR Snippet Template\n\n```markdown\n## UI Evidence\n\n- GIF: `\u003Creviewer-accessible location at the authorized destination>`\n- MP4 ZIP: `\u003Creviewer-accessible location at the authorized destination>`\n- Captions: burned-in (or link to the matching caption artifact)\n- Route: `\u002Fpath\u002Funder\u002Ftest`\n- Commit: `\u003Csha>`\n- Claim: \u003Cwhat this proves>\n```\n\n## Anti-Patterns\n\nReject these:\n- URL bar cropped out\n- Success-only clip with no applicable before→after transition or, when a user action exists, no before\u002Faction flow\n- No git SHA linkage\n- Missing captions\n- Screenshot-only evidence for flow claims\n- Manual drag-drop as the only publication path\n- Media inaccessible to the intended reviewer\n\n## Authorization vs Capability (MANDATORY)\n\nBefore choosing a capture method, distinguish three separate things:\n1. **Task authorization** — you already have authorization to do routine,\n   in-scope evidence capture; a failed OS-level capture probe does NOT mean\n   the user withheld authorization.\n2. **OS capability** — whether one process\u002Ftool can capture the screen\n   natively (e.g. a CoreGraphics\u002FScreen Recording permission check).\n3. **Evidence sufficiency** — whether the required frames and provenance can\n   be produced through an authorized, already-available alternative (e.g. a\n   scoped headless browser driver, see \"Scoped Browser Ownership\" above).\n\nRules:\n- **Never run a TCC\u002Fpermission reset as a diagnostic probe** (e.g. `tccutil\n  reset ScreenCapture`, or any command that mutates OS privacy grants) to test\n  whether capture works. This destroys unrelated apps' existing grants and is\n  not reversible from inside the agent.\n- Exhaust all authorized, scoped, headless capture alternatives (Option 1 and\n  Option 3 above) before concluding that human\u002FOS-level consent is required.\n- If genuine OS consent is required after alternatives are exhausted, report\n  the exact capability gap and the alternatives you tried —\n  do not claim the user withheld authorization and do not declare the whole goal blocked.\n- Do not fabricate a browser address bar or native chrome to satisfy the\n  Mandatory Frames table when actual capture is headless.\n\n## Reviewer Checklist\n\n1. Video is linked from the review receipt at an authorized, reviewer-accessible destination\n2. Any publication follows the authorized destination and applicable automation workflow\n3. Captions are present\n4. When a user action exists, the pre-action\u002Faction\u002Fpost-action flow is visible on both compared implementations; otherwise the applicable before→after transition is visible\n5. URL and route match claim\n6. Actual baseline and candidate source linkage is verified, not inferred from captions\n7. The reviewed evidence receipt includes matching metadata\u002Fcaption artifacts\n8. mpdecimate retained-frame count reported as kept\u002Fnominal (see Frozen-frame detection); a low count triggers provenance\u002Ftimeline review, while a constructed slideshow always fails under the canonical rule\n9. When a user action exists, each clip contains the action itself plus the before state; otherwise each clip contains the applicable before→after transition\n10. Before\u002Fafter provenance is fresh runs of each build, or labeled `derived` with source\n11. `\u002Fer` and second-opinion (`advice` skill) verdicts come from a different agent\u002Flane than the evidence producer, and name that lane\n12. An independent AI reviewer (not the author or orchestrator) judged frames extracted from the\n    published video against each acceptance step, with PASS\u002FFAIL and timestamps;\n    privacy, playback, and upload checks are separate and do not substitute\n    (`evidence-review` check 4)\n\n## Frozen-frame and slideshow detection (MANDATORY)\n\nThe canonical continuous-video prohibition is in [`evidence-standards`](..\u002Fevidence-standards\u002FSKILL.md#continuous-video-only--slideshows-are-forbidden). It is absolute: the motion probe below is diagnostic evidence, never permission to accept a screenshot sequence, and captions or named action frames never waive the prohibition.\n\nReport the mpdecimate **retained-frame count** (kept) and the nominal frame\ncount for every clip. The probe must fail closed: a failed decode or empty count\nis an error, never \"zero frames\".\n\n```bash\nset -o pipefail\nkept=$(ffmpeg -nostdin -v error -i v.mp4 -vf mpdecimate -f null -progress pipe:1 - \\\n  | grep -o '^frame=[0-9]*' | tail -1 | cut -d= -f2) || { echo \"probe FAILED\"; exit 1; }\nnominal=$(ffprobe -v error -count_frames -select_streams v:0 \\\n  -show_entries stream=nb_read_frames -of csv=p=0 v.mp4) || { echo \"ffprobe FAILED\"; exit 1; }\n[ -n \"$kept\" ] && [ -n \"$nominal\" ] || { echo \"count unavailable: FAILED\"; exit 1; }\necho \"kept=$kept nominal=$nominal\"\n```\n\nA low retained-frame count triggers provenance and timeline review; it is not\nstandalone proof of a slideshow and is not an automatic rejection of legitimate\ncontinuous footage with an idle interval. A constructed still-image sequence\nalways fails under the canonical rule regardless of its retained-frame count,\ncaption, or successful decode.\n\n## Action must be in the window (MANDATORY)\n\nWhen a user action exists, each clip must include the user action under test\n(for example the Send tap) and the before state that precedes it. A capture\nwindow anchored only to completion (e.g. trimmed to the DONE state) that omits\nthe action fails.\n\nWhen the change's observable has no user action (first paint, an error state\nrendered on load, a theme token applied at mount), record this rule as N\u002FA with\nthe reason and instead provide a state-transition clip showing the before-state\nframe and the after-state frame.\n\n## Provenance of before\u002Fafter clips (MANDATORY)\n\nBefore and after clips must come from fresh runs of each build (baseline and\ncandidate). Any re-cut, trimmed, or reused baseline clip must be labeled\n`derived` in its caption and receipt, with its source (original artifact URL,\nbuild SHA, and run). Unlabeled derived clips are INSUFFICIENT.\n\n## Reviewer independence\n\n`\u002Fer` and second-opinion (`advice` skill) verdicts on UI video evidence must come from an agent other\nthan the one that produced the evidence. Self-review does not satisfy either\ngate.\n\n## First-frame verification (MANDATORY)\n\nMoved here from `~\u002F.claude\u002FCLAUDE.md` on 2026-07-25. Applies to AGY CLI and any browser-capture pipeline.\n\n1. **Wait for page readiness before capture.** Replace fixed-delay sleeps with `page.wait_for_load_state(\"networkidle\")` AND `page.wait_for_selector(\u003Cexpected-ui-element>, state=\"visible\")`. A blank\u002Fwhite first frame is invalid evidence — it means the page had not rendered.\n2. **Verify the first frame visually before pushing.** Extract frame 1 from the MP4 and confirm it shows the expected starting state (dashboard, modal opener, etc.), not a loading screen:\n\n   ```bash\n   ffmpeg -i video.mp4 -vf \"select=eq(n\\,0)\" -vframes 1 frame1.png\n   ```\n\n3. **Reject evidence with a white\u002Fblank first frame.** Re-capture with stronger wait conditions. Do not publish a blank capture and label it as evidence.\n4. **Evidence Gate caveat:** the `evidence-gate` CI check validates `metadata.json` freshness, NOT visual content. Visual verification is the responsibility of the agent presenting the evidence — a green evidence-gate says nothing about whether the video shows anything.\n\n### Capture script standard *(your-project.com-specific)*\n\nEvery `testing_ui\u002Fcapture_*.py` script must use the shared `browser_test_helpers.py` helpers — `wait_for_page_ready()` and `verify_first_frame_not_blank()`. New scripts that re-implement waits inline are a regression.\n\n## Slack Distribution — Native Attachments Only\n\nWhen distributing video or visual evidence to Slack (channels, incident threads, or DMs):\n- **NEVER** use text-only Slack MCP tools (`conversations_add_message`) to send bare paths or GitHub URLs. Text-only message tools do not render media inline.\n- **ALWAYS** use the dedicated uploader script:\n  ```text\n  python3 ..\u002Fslack-media-upload\u002Fscripts\u002Fslack_upload.py [--dm | --channel \u003Cid>] --file \u003Cpath> [--title \u003Ctitle>...] [--thread-ts \u003Cts>] [--comment \u003Ctext>]\n  ```\n- This wraps Slack's two-step `files.getUploadURLExternal` → `files.completeUploadExternal` API so videos and GIFs render directly inline in Slack.\n","# UI Video Evidence for Visual Verification\n\n## Purpose\n\nProve user-visible behavior in a way reviewers and agents can verify quickly from the PR conversation.\n\nBefore producing or reviewing any video, apply the canonical [`evidence-standards` continuous-video rule](..\u002Fevidence-standards\u002FSKILL.md#continuous-video-only--slideshows-are-forbidden). Screenshot sequences and slideshow MP4s never satisfy video evidence.\n\n## When UI Video Is Required\n\nApply the narrow proportional exceptions in [pr-lifecycle](..\u002Fpr-lifecycle\u002FSKILL.md) first. Source-only harmless display-copy may justify media N\u002FA; a bounded static-copy rendering claim may use an actual screenshot. Other UI\u002Fbrowser video is mandatory for user-facing behavior, including:\n- Visual\u002FUI layout or styling changes\n- Click flows, form submit flows, navigation, or modal behavior\n- New\u002Fchanged browser interactions\n- Any claim of visual correctness or lack of visual regression\n\nOutside those explicit exceptions, missing applicable UI video is an evidence failure. Never waive requested interaction, streaming or native proof by calling it a string change.\n\n## Required Outputs\n\nEach video run must provide the following; the simple-static screenshot exception\nretains the canonical paired-capture, provenance, and visual-review requirements:\n- UI video (`.mp4` preferred)\n- UI fallback media (`.gif` recommended when player embed is not required)\n- Captions (burned-in preferred; `.vtt`\u002F`.srt` acceptable)\n- Git linkage (`git rev-parse HEAD` visible in recording context)\n- Media links accessible to the intended reviewer at an authorized destination\n- A browser-viewable artifact (`.gif`, commit-pinned raw asset, release asset, or native attachment)\n- A downloadable high-fidelity artifact (`.mp4`, `.mp4.zip`, or release asset)\n- Matching metadata and caption artifacts in the reviewed evidence receipt\n\n## Scoped Browser Ownership (resolve FIRST, before picking a capture method)\n\nBefore choosing how to capture evidence, check whether the target repo has its\nown browser-execution owner (e.g. `testing_ui\u002FCLAUDE.md`,\n`..\u002Fbrowser-testing\u002FSKILL.md`). If a scoped owner exists and\nforbids headed\u002Fmanual capture or Claude-in-Chrome, its policy wins — use its\ndesignated headless tool (Aside CLI\u002F`aside-mcp`, or headless Playwright). Do\nnot escalate to a native-chrome\u002Fmanual-capture requirement, and do not ask for\nScreen Recording permission, when a scoped headless path is available and not\ndocumented as blocked.\n\n## Mandatory Frames\n\nCapture this journey on each compared implementation. The pre-action frame below\nis not by itself the pre-change-code baseline; preserve both revisions and their\noriginal capture provenance under the canonical BEFORE\u002FAFTER rule.\n\n| # | Frame | Must show |\n|---|-------|-----------|\n| 1 | URL + Page Load | Full native browser URL bar with route under test, OR — when the scoped owner mandates headless capture — a genuine route\u002FURL provenance marker (printed navigation URL\u002Flog line, on-page route text, or window title) captured from the same automated session and tied to the frame timestamp |\n| 2 | Pre-action State | Initial state before action on this revision |\n| 3 | Action | Click\u002Finput\u002Fnavigation action |\n| 4 | Post-action State | Resulting state after action on this revision |\n| 5 | Git Linkage | Terminal split, devtools log, or on-page SHA marker |\n\n## Recording Options\n\n### Option 1: Scoped headless driver (Aside \u002F Playwright) — DEFAULT\nFollow `..\u002Fbrowser-testing\u002FSKILL.md`: drive the browser headlessly\nvia Aside CLI\u002F`aside-mcp` or headless Playwright, log the navigated URL\u002Froute to\nthe terminal or an overlay, and record with the scoped repo's own recorder\n(e.g. `testing_ui\u002Fstreaming\u002Fbase.py` `UIVideoRecorder`) or `ffmpeg` (Option 3).\nNever use `mcp__claude-in-chrome__*` or any headed browser for this path.\n\n### Option 2: Manual desktop capture (Kap) — LAST RESORT ONLY\nOnly when the current thread explicitly requests visible capture, the browser\nis independently verified as task-owned, and the repo permits it. Absence of a\nrepo prohibition is not authorization. Follow the shared browser-control owner;\nnever use personal\u002Fdefault Chrome, its profiles or its cookies.\n```bash\nbrew install --cask kap\n```\nRecord browser window including address bar.\n\n### Option 3: ffmpeg (headless\u002FCI)\n```bash\nffmpeg -video_size 1280x720 -framerate 10 -f x11grab -i :99 -t 30 \"\u002Ftmp\u002F${WORK_NAME:-work}.mp4\"\n```\n\n## Caption Requirements (MANDATORY)\n\nBoth tmux and UI videos must always have captions.\n\nAccepted forms:\n1. Burned-in captions in the video (preferred)\n2. Sidecar caption file (`.vtt`\u002F`.srt`) linked alongside the reviewed media artifacts\n\nUse `..\u002Fvideo-caption\u002FSKILL.md` for reliable burned-in captions.\n\n## Evidence access and authorized publication\n\nFollow `..\u002Fevidence-standards\u002FSKILL.md` for publication authority, audience, and destination. A PR, checked-in document, access-controlled receipt\u002Fstore, or authorized gist may link the evidence. For PRs governed by pr-lifecycle, its review receipts belong in the PR description; opted-in repositories also link every stage-exit receipt through its required sanitized gist URL (except a pr-lifecycle one-liner fast-path receipt, which lives in the PR body). Applicable inline viewable media and original media URLs are required there. Other authorized artifact storage does not remove that description\u002Fpublication requirement. Preserve real media, captions, exact source provenance, and reviewer access; publish only within the current authorization.\n\nThe following GitHub release example applies only when that destination is authorized. Verify the intended PR exists via `gh pr view` before creating any release or upload. Caller must provide non-empty `VIDEO_FILE` and `PREVIEW_FILE` artifacts, an explicit non-empty `RUN_ID`, an explicit non-empty `CAPTURED_SHA` matching the PR head SHA, and declare an explicit caption choice: set `CAPTION_FILE` to the actual .vtt or .srt sidecar path, or set `CAPTION_MODE=burned` when captions are burned into the video. All media and subtitle formats are verified with ffprobe prior to archive creation and publication. Packaging creates a new archive in a private temporary directory so existing user archives are never overwritten or updated with stale entries. Each run publishes to an immutable unique release tag combining the PR number, commit SHA, and run identifier without overwriting or clobbering existing releases.\n\nThis example publishes a current-candidate capture only. Retain baseline media at\nits actual source SHA through an authorized artifact route; never relabel it as\nthe PR head to satisfy this example's head-equality guard.\n\n```bash\n(\n  set -euo pipefail\n  repo=\"${REPO:-}\"\n  url_regex='^https:\u002F\u002Fgithub\\.com\u002F([^\u002F]+\u002F[^\u002F]+)\u002Fpull\u002F([1-9][0-9]*)\u002F?$'\n\n  if [[ -n \"${PR_NUMBER_OR_URL:-}\" ]]; then\n    if [[ \"$PR_NUMBER_OR_URL\" =~ $url_regex ]]; then\n      url_repo=\"${BASH_REMATCH[1]}\"\n      url_pr=\"${BASH_REMATCH[2]}\"\n      if [[ -n \"$repo\" && \"$repo\" != \"$url_repo\" ]]; then\n        echo \"Error: Conflicting repository target '$repo' vs PR URL '$url_repo'\" >&2\n        exit 1\n      fi\n      repo=\"${repo:-$url_repo}\"\n      if [[ -n \"${PR_NUMBER:-}\" && \"${PR_NUMBER}\" != \"$url_pr\" ]]; then\n        echo \"Error: Conflicting PR number '${PR_NUMBER}' vs PR URL '$url_pr'\" >&2\n        exit 1\n      fi\n      PR_NUMBER=\"$url_pr\"\n    elif [[ \"$PR_NUMBER_OR_URL\" =~ ^[1-9][0-9]*$ ]]; then\n      if [[ -n \"${PR_NUMBER:-}\" && \"${PR_NUMBER}\" != \"$PR_NUMBER_OR_URL\" ]]; then\n        echo \"Error: Conflicting PR number '${PR_NUMBER}' vs PR_NUMBER_OR_URL '$PR_NUMBER_OR_URL'\" >&2\n        exit 1\n      fi\n      PR_NUMBER=\"${PR_NUMBER:-$PR_NUMBER_OR_URL}\"\n    else\n      echo \"Error: PR_NUMBER_OR_URL must be a valid GitHub PR URL or positive PR number\" >&2\n      exit 1\n    fi\n  fi\n\n  if [[ -n \"${PR_NUMBER:-}\" && \"$PR_NUMBER\" =~ $url_regex ]]; then\n    url_repo=\"${BASH_REMATCH[1]}\"\n    url_pr=\"${BASH_REMATCH[2]}\"\n    if [[ -n \"$repo\" && \"$repo\" != \"$url_repo\" ]]; then\n      echo \"Error: Conflicting repository target '$repo' vs PR URL '$url_repo'\" >&2\n      exit 1\n    fi\n    repo=\"${repo:-$url_repo}\"\n    PR_NUMBER=\"$url_pr\"\n  fi\n\n  if ! command -v ffprobe >\u002Fdev\u002Fnull 2>&1; then\n    echo \"Error: ffprobe is required for media validation but not found in PATH\" >&2\n    exit 1\n  fi\n\n  if [[ -z \"${PR_NUMBER:-}\" || \"$PR_NUMBER\" == *\"\u003C\"* || ! \"$PR_NUMBER\" =~ ^[1-9][0-9]*$ ]]; then\n    echo \"Error: PR_NUMBER must be set to a valid PR number before publication\" >&2\n    exit 1\n  fi\n  if [[ -z \"${repo:-}\" || \"$repo\" == *\"\u003C\"* ]]; then\n    echo \"Error: REPO must be set to a valid owner\u002Frepo before publication\" >&2\n    exit 1\n  fi\n  if [[ ! \"$repo\" =~ ^[a-zA-Z0-9_.-]+\u002F[a-zA-Z0-9_.-]+$ ]]; then\n    echo \"Error: REPO must be in the format 'owner\u002Frepo'\" >&2\n    exit 1\n  fi\n  if [[ -z \"${RUN_ID:-}\" || \"$RUN_ID\" == *\"\u003C\"* ]]; then\n    echo \"Error: RUN_ID must be set to an explicit nonempty identifier before publication\" >&2\n    exit 1\n  fi\n  if [[ -z \"${CAPTURED_SHA:-}\" || \"$CAPTURED_SHA\" == *\"\u003C\"* ]]; then\n    echo \"Error: CAPTURED_SHA must be set to the explicit commit SHA captured in the evidence\" >&2\n    exit 1\n  fi\n\n  if [[ -z \"${VIDEO_FILE:-}\" || \"$VIDEO_FILE\" == *\"\u003C\"* ]]; then\n    echo \"Error: VIDEO_FILE must be set to a valid path before publication\" >&2\n    exit 1\n  fi\n  if [[ -z \"${PREVIEW_FILE:-}\" || \"$PREVIEW_FILE\" == *\"\u003C\"* ]]; then\n    echo \"Error: PREVIEW_FILE must be set to a valid path before publication\" >&2\n    exit 1\n  fi\n\n  video_file=\"$VIDEO_FILE\"\n  preview_file=\"$PREVIEW_FILE\"\n\n  if [ ! -f \"$video_file\" ] || [ ! -s \"$video_file\" ]; then\n    echo \"Error: Video file '$video_file' not found or is empty\" >&2\n    exit 1\n  fi\n  if [ ! -f \"$preview_file\" ] || [ ! -s \"$preview_file\" ]; then\n    echo \"Error: Preview file '$preview_file' not found or is empty\" >&2\n    exit 1\n  fi\n\n  video_codec=\"$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_type -of default=noprint_wrappers=1:nokey=1 \"$video_file\" 2>\u002Fdev\u002Fnull || true)\"\n  if [[ \"$video_codec\" != \"video\" ]]; then\n    echo \"Error: Video file '$video_file' does not contain a valid video stream\" >&2\n    exit 1\n  fi\n\n  preview_codec=\"$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_type -of default=noprint_wrappers=1:nokey=1 \"$preview_file\" 2>\u002Fdev\u002Fnull || true)\"\n  if [[ \"$preview_codec\" != \"video\" ]]; then\n    echo \"Error: Preview file '$preview_file' does not contain a valid video\u002Fimage stream\" >&2\n    exit 1\n  fi\n\n  if [[ -n \"${CAPTION_MODE:-}\" && \"${CAPTION_MODE:-}\" != \"burned\" ]]; then\n    echo \"Error: Unsupported CAPTION_MODE '${CAPTION_MODE}': only CAPTION_MODE=burned is supported\" >&2\n    exit 1\n  fi\n\n  if [[ -n \"${CAPTION_FILE:-}\" && \"${CAPTION_MODE:-}\" == \"burned\" ]]; then\n    echo \"Error: Cannot specify both CAPTION_FILE and CAPTION_MODE=burned: choose exactly one caption option\" >&2\n    exit 1\n  fi\n\n  if [[ \"${CAPTION_MODE:-}\" == \"burned\" ]]; then\n    caption_file=\"\"\n  elif [[ -n \"${CAPTION_FILE:-}\" && \"${CAPTION_FILE:-}\" != *\"\u003C\"* ]]; then\n    caption_file=\"$CAPTION_FILE\"\n    if [ ! -f \"$caption_file\" ] || [ ! -s \"$caption_file\" ]; then\n      echo \"Error: Caption sidecar '$caption_file' specified but not found or is empty\" >&2\n      exit 1\n    fi\n    caption_codec=\"$(ffprobe -v error -show_entries stream=codec_type -of default=noprint_wrappers=1:nokey=1 \"$caption_file\" 2>\u002Fdev\u002Fnull || true)\"\n    if [[ \"$caption_codec\" != \"subtitle\" ]]; then\n      echo \"Error: Caption file '$caption_file' does not contain a valid subtitle stream\" >&2\n      exit 1\n    fi\n  else\n    echo \"Error: Explicit caption choice required: specify CAPTION_FILE (.vtt\u002F.srt) or CAPTION_MODE=burned\" >&2\n    exit 1\n  fi\n\n  # Verify exact intended PR before any release creation or mutation\n  pr_view_json=\"$(gh pr view \"$PR_NUMBER\" --repo \"$repo\" --json number,headRefOid,url)\"\n  pr_head_sha=\"$(printf '%s' \"$pr_view_json\" | jq -r '.headRefOid \u002F\u002F empty')\"\n  pr_number_resolved=\"$(printf '%s' \"$pr_view_json\" | jq -r '.number \u002F\u002F empty')\"\n  if [[ -n \"$pr_number_resolved\" && \"$pr_number_resolved\" != \"$PR_NUMBER\" ]]; then\n    echo \"Error: Verified PR number mismatch ($pr_number_resolved vs $PR_NUMBER)\" >&2\n    exit 1\n  fi\n  if [[ -z \"$pr_head_sha\" ]]; then\n    echo \"Error: Unable to resolve head SHA for PR #$PR_NUMBER in $repo\" >&2\n    exit 1\n  fi\n\n  if [[ \"$CAPTURED_SHA\" != \"$pr_head_sha\" ]]; then\n    echo \"Error: Declared CAPTURED_SHA '$CAPTURED_SHA' does not match verified PR head '$pr_head_sha'\" >&2\n    exit 1\n  fi\n\n  sha_short=\"${CAPTURED_SHA:0:12}\"\n  tag=\"evidence-pr-${PR_NUMBER}-${sha_short}-${RUN_ID}\"\n\n  archive_scratch=\"$(\"${CLAUDE_HOME:-$HOME\u002F.claude}\u002Fskills\u002Fscratch-space\u002Fscripts\u002Fscratch-dir.sh\" tmp)\"\n  if [ -z \"$archive_scratch\" ]; then\n    echo \"Scratch resolver returned an empty path; refusing archive allocation\" >&2\n    exit 75\n  fi\n  archive_dir=\"$(mktemp -d \"$archive_scratch\u002Fevidence_archive.XXXXXX\")\"\n  zip_file=\"$archive_dir\u002F$(basename \"$video_file\").zip\"\n  trap 'rm -f -- \"$zip_file\"; rmdir -- \"$archive_dir\"' EXIT\n  zip -j \"$zip_file\" \"$video_file\"\n\n  assets=(\"$zip_file\" \"$preview_file\")\n  if [ -n \"$caption_file\" ]; then\n    assets+=(\"$caption_file\")\n  fi\n\n  if ! gh release create \"$tag\" --repo \"$repo\" --target \"$CAPTURED_SHA\" --draft --title \"PR #${PR_NUMBER} Evidence\" --notes \"\"; then\n    echo \"Error: Release '$tag' could not be created or already exists; stopping without modifying releases\" >&2\n    exit 1\n  fi\n  release_json=\"$(gh release view \"$tag\" --repo \"$repo\" --json assets,targetCommitish,url)\"\n  release_target=\"$(printf '%s' \"$release_json\" | jq -r '.targetCommitish \u002F\u002F empty')\"\n  if [[ -z \"$release_target\" || ! \"$release_target\" =~ ^[0-9a-fA-F]{40}$ ]]; then\n    echo \"Error: Unable to resolve valid target commit for release '$tag' in $repo\" >&2\n    exit 1\n  fi\n  if [[ \"$release_target\" != \"$CAPTURED_SHA\" ]]; then\n    echo \"Error: Verified release target commit '$release_target' does not match CAPTURED_SHA '$CAPTURED_SHA'\" >&2\n    exit 1\n  fi\n  gh release upload \"$tag\" --repo \"$repo\" \"${assets[@]}\"\n  release_json=\"$(gh release view \"$tag\" --repo \"$repo\" --json assets,targetCommitish,url)\"\n  release_target=\"$(printf '%s' \"$release_json\" | jq -r '.targetCommitish \u002F\u002F empty')\"\n  if [[ -z \"$release_target\" || ! \"$release_target\" =~ ^[0-9a-fA-F]{40}$ ]]; then\n    echo \"Error: Unable to resolve valid target commit for release '$tag' in $repo\" >&2\n    exit 1\n  fi\n  if [[ \"$release_target\" != \"$CAPTURED_SHA\" ]]; then\n    echo \"Error: Verified release target commit '$release_target' does not match CAPTURED_SHA '$CAPTURED_SHA'\" >&2\n    exit 1\n  fi\n  for expected_asset in \"${assets[@]}\"; do\n    name=\"$(basename \"$expected_asset\")\"\n    matches=\"$(printf '%s' \"$release_json\" | jq --arg n \"$name\" '[.assets[] | select(.name == $n)]')\"\n    count=\"$(printf '%s' \"$matches\" | jq 'length')\"\n    if [[ \"$count\" -ne 1 ]]; then\n      echo \"Error: Expected asset '$name' present $count time(s) in release readback (must be exactly 1)\" >&2\n      exit 1\n    fi\n    if [[ -z \"$(printf '%s' \"$matches\" | jq -r '.[0].url \u002F\u002F empty')\" ]]; then\n      echo \"Error: Expected asset '$name' has no usable URL in release readback\" >&2\n      exit 1\n    fi\n  done\n  printf '%s\\n' \"$release_json\"\n)\n```\n\nFrom the JSON output returned by `gh release view`, extract the uploaded asset URLs and construct `the canonical Scratch comment body`. Do not guess draft asset download URLs or invent placeholder URLs.\n\nOnce `the canonical Scratch comment body` is constructed, post the comment to the authorized PR:\n\n```bash\n(\n  set -euo pipefail\n  repo=\"${REPO:-}\"\n  url_regex='^https:\u002F\u002Fgithub\\.com\u002F([^\u002F]+\u002F[^\u002F]+)\u002Fpull\u002F([1-9][0-9]*)\u002F?$'\n\n  if [[ -n \"${PR_NUMBER_OR_URL:-}\" ]]; then\n    if [[ \"$PR_NUMBER_OR_URL\" =~ $url_regex ]]; then\n      url_repo=\"${BASH_REMATCH[1]}\"\n      url_pr=\"${BASH_REMATCH[2]}\"\n      if [[ -n \"$repo\" && \"$repo\" != \"$url_repo\" ]]; then\n        echo \"Error: Conflicting repository target '$repo' vs PR URL '$url_repo'\" >&2\n        exit 1\n      fi\n      repo=\"${repo:-$url_repo}\"\n      if [[ -n \"${PR_NUMBER:-}\" && \"${PR_NUMBER}\" != \"$url_pr\" ]]; then\n        echo \"Error: Conflicting PR number '${PR_NUMBER}' vs PR URL '$url_pr'\" >&2\n        exit 1\n      fi\n      PR_NUMBER=\"$url_pr\"\n    elif [[ \"$PR_NUMBER_OR_URL\" =~ ^[1-9][0-9]*$ ]]; then\n      if [[ -n \"${PR_NUMBER:-}\" && \"${PR_NUMBER}\" != \"$PR_NUMBER_OR_URL\" ]]; then\n        echo \"Error: Conflicting PR number '${PR_NUMBER}' vs PR_NUMBER_OR_URL '$PR_NUMBER_OR_URL'\" >&2\n        exit 1\n      fi\n      PR_NUMBER=\"${PR_NUMBER:-$PR_NUMBER_OR_URL}\"\n    else\n      echo \"Error: PR_NUMBER_OR_URL must be a valid GitHub PR URL or positive PR number\" >&2\n      exit 1\n    fi\n  fi\n\n  if [[ -n \"${PR_NUMBER:-}\" && \"$PR_NUMBER\" =~ $url_regex ]]; then\n    url_repo=\"${BASH_REMATCH[1]}\"\n    url_pr=\"${BASH_REMATCH[2]}\"\n    if [[ -n \"$repo\" && \"$repo\" != \"$url_repo\" ]]; then\n      echo \"Error: Conflicting repository target '$repo' vs PR URL '$url_repo'\" >&2\n      exit 1\n    fi\n    repo=\"${repo:-$url_repo}\"\n    PR_NUMBER=\"$url_pr\"\n  fi\n\n  if [[ -z \"${PR_NUMBER:-}\" || \"$PR_NUMBER\" == *\"\u003C\"* || ! \"$PR_NUMBER\" =~ ^[1-9][0-9]*$ ]]; then\n    echo \"Error: PR_NUMBER must be set to a valid PR number before publication\" >&2\n    exit 1\n  fi\n  if [[ -z \"${repo:-}\" || \"$repo\" == *\"\u003C\"* ]]; then\n    echo \"Error: REPO must be set to a valid owner\u002Frepo before publication\" >&2\n    exit 1\n  fi\n  if [[ ! \"$repo\" =~ ^[a-zA-Z0-9_.-]+\u002F[a-zA-Z0-9_.-]+$ ]]; then\n    echo \"Error: REPO must be in the format 'owner\u002Frepo'\" >&2\n    exit 1\n  fi\n  if [[ -z \"${CAPTURED_SHA:-}\" || \"$CAPTURED_SHA\" == *\"\u003C\"* || ! \"$CAPTURED_SHA\" =~ ^[0-9a-fA-F]{40}$ ]]; then\n    echo \"Error: CAPTURED_SHA must be set to a valid 40-character commit SHA\" >&2\n    exit 1\n  fi\n\n  comment_scratch=\"$(\"${CLAUDE_HOME:-$HOME\u002F.claude}\u002Fskills\u002Fscratch-space\u002Fscripts\u002Fscratch-dir.sh\" tmp)\"\n  comment_file=\"${COMMENT_FILE:-$comment_scratch\u002Fevidence_comment.md}\"\n  if [ ! -s \"$comment_file\" ]; then\n    echo \"Error: Comment body file '$comment_file' does not exist or is empty\" >&2\n    exit 1\n  fi\n\n  # Verify exact intended PR before posting comment\n  pr_view_json=\"$(gh pr view \"$PR_NUMBER\" --repo \"$repo\" --json number,headRefOid,url)\"\n  pr_number_resolved=\"$(printf '%s' \"$pr_view_json\" | jq -r '.number \u002F\u002F empty')\"\n  if [[ -n \"$pr_number_resolved\" && \"$pr_number_resolved\" != \"$PR_NUMBER\" ]]; then\n    echo \"Error: Verified PR number mismatch ($pr_number_resolved vs $PR_NUMBER)\" >&2\n    exit 1\n  fi\n  pr_head_sha=\"$(printf '%s' \"$pr_view_json\" | jq -r '.headRefOid \u002F\u002F empty')\"\n  if [[ -z \"$pr_head_sha\" || ! \"$pr_head_sha\" =~ ^[0-9a-fA-F]{40}$ ]]; then\n    echo \"Error: Unable to resolve valid head SHA for PR #$PR_NUMBER in $repo\" >&2\n    exit 1\n  fi\n  if [[ \"$CAPTURED_SHA\" != \"$pr_head_sha\" ]]; then\n    echo \"Error: Declared CAPTURED_SHA '$CAPTURED_SHA' does not match verified PR head '$pr_head_sha'\" >&2\n    exit 1\n  fi\n\n  target_pr=\"$PR_NUMBER\"\n  gh pr comment \"$target_pr\" --repo \"$repo\" --body-file \"$comment_file\"\n)\n```\n\nOptional path:\n- `$HOME\u002F.claude\u002Fscripts\u002Fgithub_pr_media_upload.py` may still be used when native `user-attachments` URLs are specifically desired and a valid GitHub web session cookie is available\n\nBehavior:\n- Keeps publication fully zero-touch via `gh`\n- Produces durable GitHub-hosted URLs that can be pasted into the PR description or comment\n- Avoids dependence on a browser session cookie\n\n## PR Snippet Template\n\n```markdown\n## UI Evidence\n\n- GIF: `\u003Creviewer-accessible location at the authorized destination>`\n- MP4 ZIP: `\u003Creviewer-accessible location at the authorized destination>`\n- Captions: burned-in (or link to the matching caption artifact)\n- Route: `\u002Fpath\u002Funder\u002Ftest`\n- Commit: `\u003Csha>`\n- Claim: \u003Cwhat this proves>\n```\n\n## Anti-Patterns\n\nReject these:\n- URL bar cropped out\n- Success-only clip with no applicable before→after transition or, when a user action exists, no before\u002Faction flow\n- No git SHA linkage\n- Missing captions\n- Screenshot-only evidence for flow claims\n- Manual drag-drop as the only publication path\n- Media inaccessible to the intended reviewer\n\n## Authorization vs Capability (MANDATORY)\n\nBefore choosing a capture method, distinguish three separate things:\n1. **Task authorization** — you already have authorization to do routine,\n   in-scope evidence capture; a failed OS-level capture probe does NOT mean\n   the user withheld authorization.\n2. **OS capability** — whether one process\u002Ftool can capture the screen\n   natively (e.g. a CoreGraphics\u002FScreen Recording permission check).\n3. **Evidence sufficiency** — whether the required frames and provenance can\n   be produced through an authorized, already-available alternative (e.g. a\n   scoped headless browser driver, see \"Scoped Browser Ownership\" above).\n\nRules:\n- **Never run a TCC\u002Fpermission reset as a diagnostic probe** (e.g. `tccutil\n  reset ScreenCapture`, or any command that mutates OS privacy grants) to test\n  whether capture works. This destroys unrelated apps' existing grants and is\n  not reversible from inside the agent.\n- Exhaust all authorized, scoped, headless capture alternatives (Option 1 and\n  Option 3 above) before concluding that human\u002FOS-level consent is required.\n- If genuine OS consent is required after alternatives are exhausted, report\n  the exact capability gap and the alternatives you tried —\n  do not claim the user withheld authorization and do not declare the whole goal blocked.\n- Do not fabricate a browser address bar or native chrome to satisfy the\n  Mandatory Frames table when actual capture is headless.\n\n## Reviewer Checklist\n\n1. Video is linked from the review receipt at an authorized, reviewer-accessible destination\n2. Any publication follows the authorized destination and applicable automation workflow\n3. Captions are present\n4. When a user action exists, the pre-action\u002Faction\u002Fpost-action flow is visible on both compared implementations; otherwise the applicable before→after transition is visible\n5. URL and route match claim\n6. Actual baseline and candidate source linkage is verified, not inferred from captions\n7. The reviewed evidence receipt includes matching metadata\u002Fcaption artifacts\n8. mpdecimate retained-frame count reported as kept\u002Fnominal (see Frozen-frame detection); a low count triggers provenance\u002Ftimeline review, while a constructed slideshow always fails under the canonical rule\n9. When a user action exists, each clip contains the action itself plus the before state; otherwise each clip contains the applicable before→after transition\n10. Before\u002Fafter provenance is fresh runs of each build, or labeled `derived` with source\n11. `\u002Fer` and second-opinion (`advice` skill) verdicts come from a different agent\u002Flane than the evidence producer, and name that lane\n12. An independent AI reviewer (not the author or orchestrator) judged frames extracted from the\n    published video against each acceptance step, with PASS\u002FFAIL and timestamps;\n    privacy, playback, and upload checks are separate and do not substitute\n    (`evidence-review` check 4)\n\n## Frozen-frame and slideshow detection (MANDATORY)\n\nThe canonical continuous-video prohibition is in [`evidence-standards`](..\u002Fevidence-standards\u002FSKILL.md#continuous-video-only--slideshows-are-forbidden). It is absolute: the motion probe below is diagnostic evidence, never permission to accept a screenshot sequence, and captions or named action frames never waive the prohibition.\n\nReport the mpdecimate **retained-frame count** (kept) and the nominal frame\ncount for every clip. The probe must fail closed: a failed decode or empty count\nis an error, never \"zero frames\".\n\n```bash\nset -o pipefail\nkept=$(ffmpeg -nostdin -v error -i v.mp4 -vf mpdecimate -f null -progress pipe:1 - \\\n  | grep -o '^frame=[0-9]*' | tail -1 | cut -d= -f2) || { echo \"probe FAILED\"; exit 1; }\nnominal=$(ffprobe -v error -count_frames -select_streams v:0 \\\n  -show_entries stream=nb_read_frames -of csv=p=0 v.mp4) || { echo \"ffprobe FAILED\"; exit 1; }\n[ -n \"$kept\" ] && [ -n \"$nominal\" ] || { echo \"count unavailable: FAILED\"; exit 1; }\necho \"kept=$kept nominal=$nominal\"\n```\n\nA low retained-frame count triggers provenance and timeline review; it is not\nstandalone proof of a slideshow and is not an automatic rejection of legitimate\ncontinuous footage with an idle interval. A constructed still-image sequence\nalways fails under the canonical rule regardless of its retained-frame count,\ncaption, or successful decode.\n\n## Action must be in the window (MANDATORY)\n\nWhen a user action exists, each clip must include the user action under test\n(for example the Send tap) and the before state that precedes it. A capture\nwindow anchored only to completion (e.g. trimmed to the DONE state) that omits\nthe action fails.\n\nWhen the change's observable has no user action (first paint, an error state\nrendered on load, a theme token applied at mount), record this rule as N\u002FA with\nthe reason and instead provide a state-transition clip showing the before-state\nframe and the after-state frame.\n\n## Provenance of before\u002Fafter clips (MANDATORY)\n\nBefore and after clips must come from fresh runs of each build (baseline and\ncandidate). Any re-cut, trimmed, or reused baseline clip must be labeled\n`derived` in its caption and receipt, with its source (original artifact URL,\nbuild SHA, and run). Unlabeled derived clips are INSUFFICIENT.\n\n## Reviewer independence\n\n`\u002Fer` and second-opinion (`advice` skill) verdicts on UI video evidence must come from an agent other\nthan the one that produced the evidence. Self-review does not satisfy either\ngate.\n\n## First-frame verification (MANDATORY)\n\nMoved here from `~\u002F.claude\u002FCLAUDE.md` on 2026-07-25. Applies to AGY CLI and any browser-capture pipeline.\n\n1. **Wait for page readiness before capture.** Replace fixed-delay sleeps with `page.wait_for_load_state(\"networkidle\")` AND `page.wait_for_selector(\u003Cexpected-ui-element>, state=\"visible\")`. A blank\u002Fwhite first frame is invalid evidence — it means the page had not rendered.\n2. **Verify the first frame visually before pushing.** Extract frame 1 from the MP4 and confirm it shows the expected starting state (dashboard, modal opener, etc.), not a loading screen:\n\n   ```bash\n   ffmpeg -i video.mp4 -vf \"select=eq(n\\,0)\" -vframes 1 frame1.png\n   ```\n\n3. **Reject evidence with a white\u002Fblank first frame.** Re-capture with stronger wait conditions. Do not publish a blank capture and label it as evidence.\n4. **Evidence Gate caveat:** the `evidence-gate` CI check validates `metadata.json` freshness, NOT visual content. Visual verification is the responsibility of the agent presenting the evidence — a green evidence-gate says nothing about whether the video shows anything.\n\n### Capture script standard *(your-project.com-specific)*\n\nEvery `testing_ui\u002Fcapture_*.py` script must use the shared `browser_test_helpers.py` helpers — `wait_for_page_ready()` and `verify_first_frame_not_blank()`. New scripts that re-implement waits inline are a regression.\n\n## Slack Distribution — Native Attachments Only\n\nWhen distributing video or visual evidence to Slack (channels, incident threads, or DMs):\n- **NEVER** use text-only Slack MCP tools (`conversations_add_message`) to send bare paths or GitHub URLs. Text-only message tools do not render media inline.\n- **ALWAYS** use the dedicated uploader script:\n  ```text\n  python3 ..\u002Fslack-media-upload\u002Fscripts\u002Fslack_upload.py [--dm | --channel \u003Cid>] --file \u003Cpath> [--title \u003Ctitle>...] [--thread-ts \u003Cts>] [--comment \u003Ctext>]\n  ```\n- This wraps Slack's two-step `files.getUploadURLExternal` → `files.completeUploadExternal` API so videos and GIFs render directly inline in Slack.\n",{"name":5,"description":7},"main","d57b06df00b496fc5debe2002b49987696f02a8c",".claude\u002Fskills\u002Fui-video-evidence",0,"https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills","https:\u002F\u002Fgithub.com\u002Fjleechanorg","2026-11-14 14:55:35",{"source":8,"skillName":5,"commands":53,"prompt":63,"zipAvailable":64},[54,57,60],{"tool":55,"command":56},"npx","npx skills add jleechanorg\u002Fjleechan-skills --skill ui-video-evidence",{"tool":58,"command":59},"bunx","bunx skills add jleechanorg\u002Fjleechan-skills --skill ui-video-evidence",{"tool":61,"command":62},"pnpm","pnpm dlx skills add jleechanorg\u002Fjleechan-skills --skill ui-video-evidence","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fui-video-evidence\u002FSKILL.md",true,[],[67,85,104,118,131,147],{"skillNo":68,"name":69,"nameZh":6,"description":70,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":71,"categories":72,"keywords":73,"publishedAt":40},"01M716Y5MTJ6GYJZ2ATXCJK8G4","instinct","Use when the user invokes \u002Finstinct or \u002Fin, or asks to \"message Instinct\", \"ask Instinct\", \"tell Instinct\", \"check Instinct\", or read replies from the configured peer assistant. iMessage first, WhatsApp Web as fallback.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Finstinct\u002FSKILL.md",[],[69,74,75,76,77,78,79,80,81,82,83,84],"user","when","replies","check","use","identity","whatsapp","gmail","read","message","ask",{"skillNo":86,"name":87,"nameZh":6,"description":88,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":89,"categories":90,"keywords":94,"publishedAt":40},"01M716Y4HF7FVVMJSA2CCVN5VF","hr","Compatibility alias for history-resume; produce the same fresh-state, provenance-aware resume briefing.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fhr\u002FSKILL.md",[91],{"categoryNo":92,"categoryName":93,"taxonomyType":25,"taxonomyTypeDesc":26},"01JBSEEDCAT000000000000038","人力资源",[87,95,96,97,39,98,99,100,101,102,103],"resume","compatibility","provenance","history","produce","alias","briefing","state","fresh",{"skillNo":105,"name":106,"nameZh":6,"description":107,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":108,"categories":109,"keywords":111,"publishedAt":40},"01M716Y1FFNFKFJYYKF8HQA6T8","history-resume","Resume briefing for the current repository branch or worktree using fresh state and admitted history sources.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fhistory-resume\u002FSKILL.md",[110],{"categoryNo":92,"categoryName":93,"taxonomyType":25,"taxonomyTypeDesc":26},[98,95,112,113,74,114,101,115,39,116,117,102,103],"history resume","branch","analysis","repository","worktree","sources",{"skillNo":119,"name":120,"nameZh":6,"description":121,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":124,"publishedAt":40},"01M716XWXJ8EPHK4RH9T14TR85","grok","Alias for the canonical grokbot browser conversation workflow; \u002Fgrok talks to the Grok bot the same way \u002Fdot talks to Dot.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fgrok\u002FSKILL.md",[],[120,125,126,127,39,128,100,129,34,130],"dot","bot","workflow","canonical","conversation","grokbot",{"skillNo":132,"name":133,"nameZh":6,"description":134,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":135,"categories":136,"keywords":137,"publishedAt":40},"01M70N9Q07DTE0EW5KFXMMMSJ0","codexa-bench","Compare `codexa` and normal `codex` on a fair split of comparable work by default; use `--strict` for duplicate runs of the exact same task.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fcodexa-bench\u002FSKILL.md",[],[138,139,140,78,141,39,142,143,144,145,146],"codexa bench","work","split","default","duplicate","task","compare","normal","codex",{"skillNo":148,"name":149,"nameZh":6,"description":150,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":151,"licenseFileUrl":152,"sourceHtmlUrl":153,"categories":154,"keywords":162,"publishedAt":40},"01M6C24S2X60SP8BBFGAEKPEGW","frontend-design","Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML\u002FCSS layouts, or when styling\u002Fbeautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Ffrontend-design\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Ffrontend-design\u002FSKILL.md",[155,158,161],{"categoryNo":156,"categoryName":157,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":159,"categoryName":160,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":23,"categoryName":24,"taxonomyType":25,"taxonomyTypeDesc":26},[163,164,165,78,166,167,168,74,169,170,171,33,28,172,173,174,175,176,177,178,179,180,181,182,183,184,75,185],"frontend","design","frontend design","generic","ui design","react","html","components","code","aesthetics","Production","web components","landing","applications","quality","web","css","create","examples","with","react components","web ui","pages"]