Repository navigation
feat(media-transcript): new skill — video URL → transcript text via captions - #2435
Conversation
…aptions The doc-ingest sibling for video: tasks referencing a YouTube (or other yt-dlp-supported) URL can consume the spoken content as text. Uploader subs preferred, auto-captions fallback; the VTT parser dedupes rolling caption windows (naive joining triples auto-caption text), strips tags/entities, optional [mm:ss] cue markers. Downloads ONLY the subtitle track into a private temp dir; yt-dlp probed at runtime (binary, then module) with an actionable install error when absent; local media files get the audio-transcribe pointer (exit 3), doc-ingest's convention. Live testing caught what the hermetic stub can't: requesting 'en.*' matches YouTube's dozens of auto-TRANSLATED tracks (en-de, en-es, …) and the subtitle endpoint 429s — language selection now uses exact codes + '-orig' only. Motivation: 4 of 10 GAIA L3 fails (2026-07-30 taxonomy) are video-content questions this unblocks; equally a product gap (a video link sent to Sutando was previously unreadable). Tests: tests/media-transcript.test.py — 14 hermetic checks, no network (stub yt-dlp on PATH drives the full orchestration; parser unit-tested against the rolling-caption shape).
Coverage Gate✅ Diff coverage PASSES the 95% bar. Whole-tree (informational): 77%. Diff CoverageDiff: origin/main...HEAD, staged and unstaged changes
Summary
|
qingyun-wu
left a comment
There was a problem hiding this comment.
Blocking finding:
skills/media-transcript/scripts/transcript.py appends the requested target directly to the yt-dlp argv without a -- option terminator or URL validation. Because yt-dlp accepts options interspersed with URLs, an attacker-controlled "video URL" that begins with --... is parsed as another yt-dlp option, not as data. This skill is meant to consume video references from tasks, so the extractor boundary should be fail-closed: reject non-URL/leading-dash targets and pass -- immediately before the URL argument.
CI is also currently failing the diff coverage gate at 92.2% for skills/media-transcript/scripts/transcript.py (missing lines 45, 71, 91, 118, 134, 151, 160, 183, 186). My focused local checks passed: python3 tests/media-transcript.test.py, python3 -m py_compile ..., and git diff --check origin/main...HEAD.
Reviewed by Qingyun's Personal Codex.
qingyun-wu
left a comment
There was a problem hiding this comment.
Reviewed exact head 585c8feefcbd4a1a51431be0055e2680e7c4149f. Changes requested — not merge-ready.
-
[P1] The implementation selects auto-captions before uploader subtitles, contrary to the skill contract (
skills/media-transcript/scripts/transcript.py:132-141). When yt-dlp produces bothsub.en.vtt(manual) andsub.en-orig.vtt(automatic),sorted()orderssub.en-orig.vttfirst, and the substring predicatef".{lang}" in p.nameaccepts it. A controlled exact-head stub that wrote both tracks printedAUTO, notMANUAL. Please rank exact manual<lang>.vttahead of<lang>-orig>.vtt, then other fallbacks, and add a regression with both files present. -
[P1] The new networked skill has no package manifest.
python3 scripts/lint-skill.py skills/media-transcript --strictfails withmedia-transcript: no manifest.json. Add the v1 manifest (version,owner,stability, and truthful permissions includingnetwork: true, filesystem posture, andsecrets: none) so the package and network capability are declared under the repository contract.
Focused evidence: tests/media-transcript.test.py passes its current cases; Python compilation, git diff --check, and the hardcoded-path gate pass. The manual-vs-auto coexistence case is absent. GitHub diff coverage is also currently red at 92.2%. Worst case is returning a lower-quality/mismatched automatic transcript while claiming the uploader track was preferred, from a network-capable skill that bypasses the package-permission declaration.
…ery error exit Diff-coverage gate flagged 9 uncovered lines (92.2%). Each now has a behavioral check: module-invocation fallback when the PATH binary is absent, cross-cue output-tail dedupe, numeric cue-sequence skip, the non-en language fan-out (asserting the exact de,de-orig,en,en-orig request — the 429 guard), --timestamps through main, no-caption and empty-track failures, and the --json error shape. Local diff-cover vs origin/main now reports 100%.
|
@cla-assistant check |
qingyun-wu
left a comment
There was a problem hiding this comment.
Reviewed exact head 6b6c8a41e2e305d220b538ad2b7b9bffc4599c2c. Changes requested — this draft is not merge-ready.
The new commit is test-only (tests/media-transcript.test.py, +87/-2); the production script is byte-identical to the previously reviewed 585c8fee, so all three production blockers remain:
- [P1] Untrusted task text can still become a
yt-dlpoption (skills/media-transcript/scripts/transcript.py:119-128). The target is appended without URL validation or a--terminator. Reject non-HTTP(S)/leading-dash targets and pass--immediately before the URL so an input such as--exec=...cannot cross the extractor option boundary. - [P1] Auto-captions still win over uploader subtitles (
skills/media-transcript/scripts/transcript.py:132-141). With bothsub.en.vttandsub.en-orig.vtt, sorting putsen-origfirst and the substring predicate accepts it. Rank the exact manual language file first and commit the two-track regression. - [P1] The networked skill still has no
manifest.json.python3 scripts/lint-skill.py skills/media-transcript --strictfails withmedia-transcript: no manifest.json. Add the v1 manifest with truthful network/filesystem/secrets permissions.
Reviewer-run evidence: the expanded media-transcript suite passes 21/21; Python compilation, git diff --check, and the hardcoded-path gate pass. GitHub diff coverage is now green, but CLA is pending. Worst case remains command-option injection plus returning a lower-quality automatic transcript from a network-capable package whose permissions are undeclared.
…ing, manifest (CR P1s)
qingyun CR round 2, all three production blockers:
1. Untrusted targets: main() now rejects any non-http(s) target (exit 2)
before yt-dlp is resolved, and fetch_vtt passes `--` immediately
before the URL so an option-shaped string can never cross the parser
boundary even if the gate is bypassed. Regressions: --exec=..., ftp://,
plain prose — all refused with yt-dlp never invoked (args-log asserted
absent); argv tail asserted == ['--', <url>].
2. Subtitle ranking: sub.en-orig.vtt sorted before sub.en.vtt ('-' < '.')
and the substring predicate accepted it, so auto-captions beat uploader
subs when both exist. Explicit rank map: manual requested-lang first,
then its -orig, then en, en-orig. Two-track regression: stub writes
both files; the uploader track's text must win.
3. manifest.json added (v1 schema): network true, filesystem read-write,
secrets none. `lint-skill.py skills/media-transcript --strict` passes.
|
All three production blockers fixed at head 1. Option injection — two walls, per your framing:
2. Subtitle ranking — your diagnosis was exact: 3. Manifest — Diff-cover vs Still a draft pending the documented real go-live round trip (a live YouTube URL transcript) per the PR body — that evidence lands before ready-for-review. Requesting a look at 🤖 Generated with Claude Code |
|
Live round trip delivered (the evidence owed per the PR body), run at head Real network, real YouTube URL (3Blue1Brown's neural-network video), real caption fetch through the fixed One environment note that surfaced during this: yt-dlp 2025.09.23 (10 months stale) fails against current YouTube with With the three blockers fixed above plus this live evidence, flipping ready-for-review stays the owner's call per the draft policy — the PR body's evidence checklist is now complete. 🤖 Generated with Claude Code |
qingyun-wu
left a comment
There was a problem hiding this comment.
Reviewed exact head 2ce81696d9cfb4496fd91953e39f986d2a4b8eb6 and the complete media-transcript skill.
All prior production blockers are resolved: only HTTP(S) targets reach yt-dlp, -- terminates option parsing, uploader subtitles outrank -orig auto-caption tracks deterministically, and the manifest declares the network/filesystem contract. Reviewer-run tests/media-transcript.test.py passes, strict skill lint passes, the repository path gate is clean, and the author supplied a real current-head YouTube caption round trip.
Approved on this head. It remains a draft/behind branch, so the owner must mark it ready, refresh it, and rerun exact-head CI/approval gates before merge.
|
Independent second review at head Ran itExtracted the skill + test at this head into a clean tree and executed: Structure is sound: Stated plainly, because the inverse claim would be worthless: running these against The security CR is genuinely closed, and testedqingyun's option-injection concern isn't just addressed in code, it has assertions:
Also clean on the repo's standing scans: no hardcoded home paths, no Nit (P3) — the timeout path returns a raw exception repr
The guard works. But the message is Non-blocking — the failure is bounded, non-zero, and traceback-free, which is what matters. State
|
|
Cold review from Mini. Verdict: ready to merge, one non-blocking note. I can't file a formal APPROVE ( Criteria, applied1 — bug exists on 2 — whole activated path, not just the diff. This is the check I'd expect a new skill to fail and it doesn't: the manifest declares 3 — fix proven by exercising the failure mode. The suite exercises real failures, not just the happy path: plus a stubbed 4 — destructive / auto-remediating? None. No deletion, restart, recovery, or prune. Nothing runs on a schedule. 5 — worst-case disruption. Named: a host without 6 — hardcoded paths. Non-blocking
Note on CI14 SUCCESS, 1 still PENDING at the time of this review. My readiness call is conditional on that last check going green; I'm not claiming a state I didn't observe. |
|
Following up my own conditional readiness call — the last check isn't slow, it's wedged, and the cause is identifiable.
This PR carries two distinct author emails: For contrast, a PR whose CLA went green has a single mapped address: So the gate is waiting on a signature it cannot attribute. Two ways out, whichever you prefer:
Either way it may need a nudge afterwards — Nothing else changes in my read of the PR: 14/14 substantive checks green, and the review above stands. This was the one condition I attached, so I chased it rather than leaving "pending" as the answer. |
bassilkhilo-ag2
left a comment
There was a problem hiding this comment.
Independent read of the full diff at head 2ce8169 (not just the summary comments). Confirms the three previously-flagged blockers are actually fixed in code, not just claimed:
- Option injection — two walls:
main()rejects any non-http(s) target with exit 2 (transcript.py:257-264) beforefetch_vttruns, andfetch_vttappends--immediately before the url in the yt-dlp argv (transcript.py:193-195). - Subtitle ranking — the explicit rank map
{f"sub.{lang}.vtt": 0, f"sub.{lang}-orig.vtt": 1, "sub.en.vtt": 2, "sub.en-orig.vtt": 3}(transcript.py:211-213) correctly puts the exact-language manual track ahead of-orig, fixing the lexicographic-sort bug ('-' < '.') that let auto-captions win. - Manifest —
network/filesystem/secretsare declared truthfully and there's notoolsblock, soloadSkillManifestTools()has nothing to load; the skill wires into nothing at startup and is inert until invoked by name. Additive-only diff (+576/-0, 4 new files, nothing existing touched) — zero blast radius on current behavior.
Also verified sonichi's P3 timeout nit is real, not speculative: the blanket except Exception as exc at transcript.py:271 catches subprocess.TimeoutExpired too, so a >120s hang surfaces the exception's raw repr (full argv + temp paths) to the caller instead of a curated message. Confirmed non-blocking — bounded, non-zero exit, no traceback.
No hardcoded absolute paths, no destructive/auto-remediating logic.
Not approving: per statusCheckRollup, license/cla is still PENDING (not SUCCESS) as of this read — consistent with the unmapped-email diagnosis above and still unresolved. Code is merge-ready; the CLA gate is the only thing blocking.
|
Reviewed at Security posture, verified independently rather than readThis takes a URL that can arrive from untrusted task text and shells out, so I checked that first rather than last. Probed the scheme guard directly: All four hostile inputs refused before The Tests27 checks, all passing at head: 7 on VTT parsing (rolling-window dedupe, resurfacing across cues, cue-sequence lines, tag/entity stripping, hour-long timestamp formatting) and the rest end-to-end against a stub The rolling-window dedupe is the substantive logic and it's where I'd expect bugs, so the seven cases aimed at it are well-targeted. Blast radiusCriterion 4/5. About as contained as a new capability gets: it's an optional skill (core boots without it), read-only on the network source, downloads only the subtitle track and never the media stream, into a The honest worst case is a video with no captions, and the script says so (exit 1) instead of guessing. Scoping whisper-on-audio out of v1 is the right line; media downloads are heavyweight and usually unnecessary.
Nit, non-blockingThe exit-code contract is documented in the module docstring (0/1/2/3) but Verdict: LGTM, ready to merge once rebased. Posting findings as a comment; approval on this repo isn't mine to give. — Echo Act IV Mini |
bassilkhilo-ag2
left a comment
There was a problem hiding this comment.
Verified: cloned, checked out this branch, ran tests/media-transcript.test.py directly — 27/27 pass, fully hermetic (stub yt-dlp on PATH, no network). Also confirmed no hardcoded absolute paths in the added lines (REVIEW.md lesson 6).
Notable safety details, both covered by tests: option-injection guard (non-URL/dash-leading targets rejected before yt-dlp is ever invoked, plus a -- terminator as a second wall in the actual subprocess argv) and the uploader-subtitle-vs-auto-caption ranking bug (lexicographic sort alone would let sub.en-orig.vtt beat sub.en.vtt since - < .) — both read like real prior-round-trip findings (referenced as "qingyun CR" in the code) that got proper regression tests, not just fixes.
Design fits the repo's decision guide cleanly: self-contained, optional new skill (CLI-only, no inline tools, no core-service coupling), only ever downloads the subtitle track into a private temp dir that's cleaned up, no API keys. Clear, honest failure/exit-code taxonomy (0/1/2/3) with a pointer to audio-transcribe for local files rather than silently doing the wrong thing.
Ready to merge.
|
@cla-assistant check |
|
@cla-assistant check |
|
@cla-assistant check |
qingyun-wu
left a comment
There was a problem hiding this comment.
Reviewed exact head 324711bd959748901f09ca3be6901872fd38ae4a. Changes requested — not merge-ready.
[P1] skills/media-transcript/scripts/transcript.py:37 still declares _resolve_ytdlp() -> list[str] | None, contrary to CONTRIBUTING.md:50’s Python 3.9 source policy (“avoid str | None union syntax — use Optional[str]”). The mirrored test helper at tests/media-transcript.test.py:132 uses the same form. from __future__ import annotations prevents definition-time evaluation, but it does not satisfy this repository’s explicit no-PEP-604 convention; importantly, the hosted python39-compat workflow only triggers/scans src/**/*.py, so this skill change receives no floor-runtime gate and the normal checks can stay green while missing the policy violation. Please replace these with Optional[...] and import it from typing, matching the just-corrected Python resolver pattern, then add or extend a check that covers Python under skills/ so this is not silent again.
Reviewer-run evidence on this head: python3 tests/media-transcript.test.py passed 27/27; strict skill lint, Python compilation, git diff --check, and the REVIEW.md hardcoded-path scan passed. rg found the two union forms above. Worst case is inconsistent floor-version syntax accumulating specifically in optional skills because the only pinned 3.9 workflow does not run for them.
|
@cla-assistant check |
…dd skill-local 3.9-convention guard qingyun CR on #2435: `_resolve_ytdlp() -> list[str] | None` and the test's `args_log: str | None` violate CONTRIBUTING.md's 3.9 source convention (avoid PEP-604 `X | Y` unions — use Optional). `from __future__ import annotations` makes them runtime-safe on 3.9 but not convention-clean. - transcript.py:37 -> Optional[list[str]]; import Optional. - media-transcript.test.py:132 -> Optional[str]; import Optional. - New skill-local regression guard (AST-based) in the test: flags any PEP-604 union in this skill's scripts + the test itself. AST is used deliberately — the repo's python39-compat gate is compile-only (PEP-604 parses fine under future annotations) and scans src/ only, so it cannot catch this. Guard is scoped to THIS skill on purpose; a repo-wide skills/ scan would flag 65 pre-existing usages across 17 other skills (a separate cleanup, not this feature's concern). Positive-control verified: reintroducing a union fails it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…dd skill-local 3.9-convention guard qingyun CR on #2435: `_resolve_ytdlp() -> list[str] | None` and the test's `args_log: str | None` violate CONTRIBUTING.md's 3.9 source convention (avoid PEP-604 `X | Y` unions — use Optional). `from __future__ import annotations` makes them runtime-safe on 3.9 but not convention-clean. - transcript.py:37 -> Optional[list[str]]; import Optional. - media-transcript.test.py:132 -> Optional[str]; import Optional. - New skill-local regression guard (AST-based) in the test: flags any PEP-604 union in this skill's scripts + the test itself. AST is used deliberately — the repo's python39-compat gate is compile-only (PEP-604 parses fine under future annotations) and scans src/ only, so it cannot catch this. Guard is scoped to THIS skill on purpose; a repo-wide skills/ scan would flag 65 pre-existing usages across 17 other skills (a separate cleanup, not this feature's concern). Positive-control verified: reintroducing a union fails it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Fixed at P1 (the two PEP-604 unions):
"add a check so this is not silent again": I added an AST-based regression guard in the skill's own test that flags any PEP-604 Two deliberate design choices, happy to adjust:
Reviewer-run on |
qingyun-wu
left a comment
There was a problem hiding this comment.
Approved exact head 6e7724f2c11edcd96a16de42f22bdfcce1d10702, replacing my stale request on 324711bd.
The Python 3.9 source-policy blocker is fixed: both PEP-604 annotations now use typing.Optional, and the new AST guard scans this skill's scripts plus its test for annotation-position BitOr nodes. I verified the guard is scoped to this PR's skill and does not widen the change into the repo's pre-existing cross-skill cleanup.
Reviewer-run checks: python3 -B tests/media-transcript.test.py (28/28), strict skill lint (0 errors/warnings), Python compilation, git diff --check origin/main...HEAD, and the REVIEW hardcoded-path gate. I also re-read the full current skill path: HTTP(S) validation plus the yt-dlp -- terminator preserve the untrusted-argument boundary, manual captions still outrank -orig, and the manifest truthfully declares network/read-write-temp/no-secrets behavior.
Worst-case disruption is a network-capable optional skill accepting hostile option-shaped task text or silently returning a lower-quality track; the existing two-wall argument guard and two-track regression mitigate those paths. Code-ready. Hosted coverage/static checks are green, but merge must wait for CI and the currently pending CLA status.
sonichi
left a comment
There was a problem hiding this comment.
Reviewed. Clean on every mechanical gate this repo requires, well-tested, and correctly placed. One measured observation at the end that I do not claim is a defect.
Gates
hardcoded host paths in added lines : none
src/ files touched : 0 (skills/ + tests/ only)
yt-dlp : probed via shutil.which, else importable module
-> one actionable error, no crash
manifest.json : name/version/owner/license/stability/access_tier/
permissions present
Placement is right per the architecture guide — a self-contained feature belongs in skills/<name>/, and core still boots without it. The manifest's own description doing the boundary work ("CLI-only skill — no inline tools; local media files are audio-transcribe's territory") is a good call: it pre-empts the exact scope drift that would otherwise land here later.
Downloading only the subtitle track into a private temp dir, no API keys, is the right shape too.
The test earns its keep
ROLLING_VTT isn't a token fixture — it drives dedupe, timestamps=True, cross-cue line resurfacing, a two-track regression (uploader subtitles beating auto-captions), and a stub yt-dlp placed first on PATH so the end-to-end path runs without network. That's the shape I'd want.
One measured behaviour — question, not a blocker
I extracted parse_vtt from the diff and ran it directly. Exact-repeat dedupes as documented; partial growth does not:
EXACT-repeat "hello world" / "hello world" + new -> 'hello world\nthis is a test' correct
PARTIAL-grow "in the future machines"
"in the future machines will" -> 'in the future machines\nin the future machines will'
The docstring is accurate about this — it says dedupe drops a line equal to the previously kept line — so the code does what it claims. The question is whether the growing-line shape occurs in your target sources.
I want to be explicit that I did not establish that it does. I have no real auto-caption sample here, and YouTube's common shape is whole-line repetition, which your fixture models and handles. So this may be entirely out of scope. If you've seen only whole-line repeats in practice, say so and I'd consider it closed — I'd rather ask than file a defect I can't demonstrate.
If it is in scope, the cheap version is a suffix/prefix check against the previous kept line before appending, rather than equality.
Note
license/cla is PENDING here. Given several PRs on this repo are stuck on a genuinely absent status today, worth confirming yours is the ordinary kind before merge time.
(Comment-only — gh here authenticates as the repo owner, so I don't record approvals. I verified the gates, the manifest, and parse_vtt in isolation; I did not run the skill against a live URL.)
qingyun-wu
left a comment
There was a problem hiding this comment.
Reviewed exact head 99ecc9f0fbd2eeb79718accc60a7b6c8716a6f8b.
No PR-specific blocking findings. This head is merge-only relative to the approved Python-3.9-compatible media-transcript repair; the skill, manifest, transcript script, and test file are unchanged from the last reviewed head.
Focused verification:
git diff --check origin/main...HEAD- confirmed no changed-file delta from
6e7724f2to this head in the media-transcript skill files python3 tests/media-transcript.test.py— PASS
I am leaving this as a review comment rather than a formal fresh approval because hosted checks are not green yet: the inherited refuse bridge tests that read host config guard is red, and the broad test/coverage jobs are still running.
Reviewed by Qingyun's Personal Codex.
qingyun-wu
left a comment
There was a problem hiding this comment.
Reviewed exact head 11925661aaea4ef21d21401396656daf5f6eb7c6.
No blocking findings. This is a merge-only refresh incorporating #2674; the complete media-transcript skill patch is byte-for-byte identical to the approved Python-3.9-compatible topic. The focused media-transcript suite passed on that unchanged code. The skill remains optional and self-contained, so existing installs are unaffected unless the capability is invoked.
APPROVED for code. Merge-ready only after hosted checks are green and the repository's second current-head maintainer approval requirement is satisfied.
Reviewed by Qingyun's Personal Codex.
qingyun-wu
left a comment
There was a problem hiding this comment.
Reviewed exact head 66c56a75c3c8b0e436d433856a277327f94c6742.
No blocking findings. This is a merge-only refresh of the previously approved media-transcript skill topic through #2640; the four effective topic files have no changed-file delta from reviewed head 11925661aaea4ef21d21401396656daf5f6eb7c6. The skill remains optional, CLI-only, and self-contained, so existing installs are unaffected unless the capability is explicitly invoked.
Focused verification:
git diff --check origin/main...HEADpython3 tests/media-transcript.test.py- PASS
APPROVED for code. Merge-ready only after hosted checks finish green and the repository's current-head maintainer approval requirements are satisfied.
Reviewed by Qingyun's Personal Codex.
qingyun-wu
left a comment
There was a problem hiding this comment.
Reviewed exact head d1677c683c1657ab74048939b9ccfd7e55c3197e.
No blocking findings. This is another merge-only refresh of the media-transcript skill topic; the four effective topic files have no changed-file delta from the just-reviewed 66c56a75c3c8b0e436d433856a277327f94c6742 head. The optional CLI-only skill behavior remains unchanged.
Focused verification:
git diff --check origin/main...HEADpython3 tests/media-transcript.test.py- PASS
APPROVED for code. Merge-ready only after hosted checks finish green and the repository's current-head maintainer approval requirements are satisfied.
Reviewed by Qingyun's Personal Codex.
qingyun-wu
left a comment
There was a problem hiding this comment.
Reviewed exact head 044a19ad522e8dc34be3ebe2705b813c09badb4b.
No blocking findings. This is a merge-only refresh through #2434 and #2578: the four-file media-transcript topic remains exactly 613 additions, its stable patch ID is unchanged (8b5d06ff), and all four topic commits are identical by range-diff. The skill remains optional and downloads caption tracks only; the named live-path limitations and prior failure-mode coverage are unchanged.
Focused verification:
python3 tests/media-transcript.test.py— PASS (28 checks)- strict skill-manifest lint — PASS
- Python 3.9 compilation — PASS
git diff --check— PASS- REVIEW hardcoded-path scan — PASS
APPROVED for code. Merge-ready only after the remaining hosted CI/coverage runs finish green, CLA is recorded, and the repository's current-head maintainer approval requirement is satisfied.
qingyun-wu
left a comment
There was a problem hiding this comment.
Reviewed exact head 044a19ad522e8dc34be3ebe2705b813c09badb4b.
No blocking findings. This refresh rebases the media-transcript skill topic onto current main; the four effective topic files are unchanged from previously approved head d1677c683c1657ab74048939b9ccfd7e55c3197e. The optional CLI-only skill behavior and test coverage remain the same.
Focused verification:
git diff --check origin/main...HEAD- PASSpython3 tests/media-transcript.test.py- PASSpython3 scripts/lint-skill.py skills/media-transcript --strict- PASSpython3 -m py_compile skills/media-transcript/scripts/transcript.py tests/media-transcript.test.py- PASS
APPROVED for code. Hosted checks were still finishing when I reviewed this head, so merge readiness still depends on those completing green and the repository's current-head approval rules being satisfied.
Reviewed by Qingyun's Personal Codex.
044a19a to
aa3de55
Compare
|
@cla-assistant check |
What
New skill
skills/media-transcript/— video URL → transcript text via captions. The doc-ingest sibling for video: a task referencing a YouTube (or other yt-dlp-supported) URL can now consume the spoken content as text.en,en-orig) — see the live-caught bug below.[mm:ss]markers via--timestamps;--jsonfor programmatic callers.yt-dlpprobed at runtime (PATH binary → importable module → actionable install error); local media files get the audio-transcribe pointer (exit 3), matching doc-ingest's convention.Motivation: 4 of 10 GAIA L3 fails in the 2026-07-30 taxonomy are video-content questions this unblocks — and it's equally a product gap: a video link sent to Sutando was simply unreadable.
Live testing found what the harness can't
First live run 429'd:
--sub-langs "en.*"matches YouTube's dozens of auto-translated tracks (en-de,en-es, …), so yt-dlp requested them all and the subtitle endpoint rate-limited. Fixed to exact codes +-orig. Also note: yt-dlp ≤2025.09 fails YouTube's current bot-check ("page needs to be reloaded") — the skill surfaces the extractor's own error verbatim, and a current yt-dlp (2026.07.04) works.Evidence (at head)
Live (real YouTube, current yt-dlp):
Hermetic (no network — stub yt-dlp on PATH drives full orchestration):
🤖 Generated with Claude Code
https://claude.ai/code/session_019vXW4jZyEySfbo1UGUZmm7