Turn YouTube videos into local, agent-ready transcripts.
Project description
YouTube Transcribe
A local-first CLI that turns a YouTube video into a clean, agent-ready transcript.
YouTube Transcribe downloads the video's native audio with yt-dlp, transcribes it locally with faster-whisper, and writes a portable Markdown file. It can also preserve word-level timestamps, WebVTT subtitles, and the original audio.
- No transcription API key or per-minute fee
- Local speech-to-text on macOS, Linux, and Windows
- Stable Markdown and versioned JSON outputs
- Optional transcript cleanup with an existing Codex CLI or Claude Code login
- Agent Skill included for Codex, Claude Code, and compatible tools
Install
Requirements:
- Python 3.10 or newer
- Enough disk space and memory for the selected Whisper model
Install the latest stable release, its dependencies, and the Agent Skill:
curl -fsSL https://raw.githubusercontent.com/kaveniohq/youtube-transcribe/main/install.sh | bash
The installer creates an isolated environment, exposes the command under
~/.local/bin, installs the skill for Codex and Claude Code, and runs
youtube-transcribe doctor. If ~/.local/bin is not on your PATH, it prints
the exact command to add it.
Prefer installing manually? Use pipx:
pipx install kavenio-youtube-transcribe
youtube-transcribe install-skill
youtube-transcribe doctor
Quick start
Transcribe a video:
youtube-transcribe "https://www.youtube.com/watch?v=VIDEO_ID"
The first run downloads the selected Whisper model. The default base model is
a practical speed/quality compromise.
Usage
| What you want | Command | Result |
|---|---|---|
| Create a transcript | youtube-transcribe "URL" |
transcript.md |
| Choose an output location | youtube-transcribe "URL" --output-dir ./transcripts |
One video folder inside ./transcripts |
| Add word and segment timestamps | youtube-transcribe "URL" --timestamps |
Markdown, versioned JSON, and WebVTT |
| Keep the downloaded audio | youtube-transcribe "URL" --keep-audio |
Transcript plus the native WebM/M4A audio |
| Refine with Codex CLI | youtube-transcribe "URL" --codex |
Locally transcribed, then text-edited with Codex |
| Refine with Claude Code | youtube-transcribe "URL" --claude |
Locally transcribed, then text-edited with Claude |
| Use a faster model | youtube-transcribe "URL" --model tiny |
Faster draft with lower accuracy |
| Use a more accurate model | youtube-transcribe "URL" --model small |
Slower transcript with higher accuracy |
| Fix the spoken language | youtube-transcribe "URL" --language en |
Skips language auto-detection |
| Use NVIDIA CUDA | youtube-transcribe "URL" --device cuda |
GPU inference with supported CUDA setup |
| Use browser authentication | youtube-transcribe "URL" --cookies-from-browser chrome |
Lets yt-dlp read the selected local browser session |
| Protect existing artifacts | youtube-transcribe "URL" --no-overwrite |
Fails instead of replacing output files |
| Install the Agent Skill | youtube-transcribe install-skill |
Adds the skill to Codex and Claude discovery locations |
| Check the installation | youtube-transcribe doctor |
Dependency and update status |
Options can be combined:
youtube-transcribe "URL" \
--output-dir ./transcripts \
--model base \
--timestamps \
--codex
Run youtube-transcribe --help for the complete command reference.
Output
Each run creates a deterministic folder named from the video title and ID:
steam-machine-8cDatzBIufQ/
└── transcript.md
With --timestamps:
steam-machine-8cDatzBIufQ/
├── transcript.md
├── transcript.json
└── timestamps.vtt
Add --keep-audio to retain the native audio file in the same folder.
| Artifact | Created when | Purpose |
|---|---|---|
transcript.md |
Always | Readable transcript with source provenance |
transcript.json |
--timestamps |
Versioned machine contract with raw segment and word timing |
timestamps.vtt |
--timestamps |
Subtitles for players and tools that support WebVTT |
audio.webm or audio.m4a |
--keep-audio |
Original native audio selected by yt-dlp |
The CLI writes progress to stderr and final artifact paths to stdout, which makes it safe to use in scripts and agent workflows:
[download] YouTube audio [████████████████████] 100%
[model] Download Whisper base [████████░░░░░░░░░░░░] 40%
[transcribe] Speech to text [██████████░░░░░░░░░░] 50%
[write] Agent-ready artifacts
Transcript format
Markdown begins with YAML-compatible provenance followed by the complete transcript:
---
transcript_schema: 1
title: "Example video"
source: "https://www.youtube.com/watch?v=..."
video_id: "..."
language: "en"
transcription_model: "base"
edited_by: "none"
transcript_data: null
timestamps: null
---
# Example video
Complete transcript...
With --timestamps, transcript.json is the canonical machine-readable
artifact. It keeps immutable raw Whisper timing separate from optionally edited
prose. The normative schema is
transcript-v1.schema.json.
Optional AI editing
No editor is selected by default. --codex and --claude deliberately start a
separate command-line editor process after local transcription; they may use
the allowance associated with your existing login.
The editor receives transcript text through standard input and cannot change the raw timestamp data:
youtube-transcribe "URL" --codex --timestamps
youtube-transcribe "URL" --claude --timestamps
Codex runs ephemerally in a read-only sandbox without user execution rules. Claude runs without built-in tools, MCP servers, slash commands, Chrome integration, or session persistence. Both run from an empty temporary directory.
Use with AI agents
The repository includes a portable Agent Skill that teaches compatible agents when to run the CLI, which options to select, and which generated file to read.
The CLI package bundles this skill. Install it with:
youtube-transcribe install-skill
This works on Linux, macOS, and Windows and writes:
~/.agents/skills/youtube-transcribe # Codex and compatible agents
~/.claude/skills/youtube-transcribe # Claude Code
Use --target codex or --target claude to install only one copy. Rerunning
the command safely updates an unchanged managed skill. Locally modified files
are preserved unless you explicitly pass --force. Run it again after
upgrading the CLI to install the bundled skill version.
Restart an already-running agent, then ask naturally:
Transcribe https://www.youtube.com/watch?v=VIDEO_ID
Transcribe this video with timestamps: https://youtu.be/VIDEO_ID
Use $youtube-transcribe to turn this video into notes: https://youtu.be/VIDEO_ID
Use /youtube-transcribe to create subtitles for https://youtu.be/VIDEO_ID
The active agent does not need --codex or --claude; those options start a
second editor process.
Local development
git clone https://github.com/kaveniohq/youtube-transcribe.git
cd youtube-transcribe
python -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
pytest
On Windows PowerShell, activate the environment with:
.venv\Scripts\Activate.ps1
Before submitting a change, run:
ruff check src tests
ruff format --check src tests
pytest --cov=youtube_transcript --cov-fail-under=80
python -m build
python -m twine check dist/*
Development references:
AGENT.md— setup, architecture, invariants, and agent-facing implementation guidanceCONTRIBUTING.md— contribution and verification rulesARCHITECTURE.md— detailed contracts, design decisions, and implementation evidenceRELEASING.md— versioning and release procedure
Default tests are offline: they do not download videos or models and do not invoke Codex or Claude.
How it works
YouTube URL
-> yt-dlp native audio download
-> local faster-whisper transcription
-> optional Codex or Claude text editing
-> atomic Markdown / JSON / WebVTT output
Provider-specific code stays behind small adapters. Temporary downloads are cleaned automatically, and final artifacts are written only after the requested pipeline succeeds.
Current limitations
- One video per invocation; playlists and channels are not supported.
- Transcripts over 600,000 characters are not sent to an optional editor.
- Live streams, members-only videos, regional restrictions, and YouTube bot challenges depend on yt-dlp and may require browser cookies.
- The first transcription for a model requires a model download.
The package supplies yt-dlp's supported Deno runtime and uses faster-whisper's PyAV decoder. A global JavaScript runtime, FFmpeg, and FFprobe are not required.
Updates
After a successful interactive run, the CLI checks PyPI at most once every seven days and prints a notice when a newer version is available. It never installs updates, changes stdout, or sends transcript/source metadata.
Set YOUTUBE_TRANSCRIBE_NO_UPDATE_CHECK=1 to disable update checks.
Contributing
Issues and focused pull requests are welcome. Please read
CONTRIBUTING.md before making a change and include tests
for behavior changes.
License
Licensed under the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kavenio_youtube_transcribe-0.1.0.tar.gz.
File metadata
- Download URL: kavenio_youtube_transcribe-0.1.0.tar.gz
- Upload date:
- Size: 52.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
85dc928b130e9cc2f9ae0b6822634758bbbd33edb6c125a0e44707c12e38aed1
|
|
| MD5 |
3a59dbdf4f11b3ce12c5cc018e1dbcbe
|
|
| BLAKE2b-256 |
d92126af0371ab0c473f0d61d9c8f7662732b74cde5da1765b59a31ac586b8a6
|
Provenance
The following attestation bundles were made for kavenio_youtube_transcribe-0.1.0.tar.gz:
Publisher:
release.yml on kaveniohq/youtube-transcribe
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kavenio_youtube_transcribe-0.1.0.tar.gz -
Subject digest:
85dc928b130e9cc2f9ae0b6822634758bbbd33edb6c125a0e44707c12e38aed1 - Sigstore transparency entry: 2248790468
- Sigstore integration time:
-
Permalink:
kaveniohq/youtube-transcribe@162f04fe0e37241b8d2d239741a3d1e0b4aa8290 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/kaveniohq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@162f04fe0e37241b8d2d239741a3d1e0b4aa8290 -
Trigger Event:
push
-
Statement type:
File details
Details for the file kavenio_youtube_transcribe-0.1.0-py3-none-any.whl.
File metadata
- Download URL: kavenio_youtube_transcribe-0.1.0-py3-none-any.whl
- Upload date:
- Size: 32.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c5b29116996799eabf249ffe062d660c7faa1bf14dc5a2171cf21079b91dcf7
|
|
| MD5 |
802e222e52abd758882070fc6459f16b
|
|
| BLAKE2b-256 |
3a216c5cd36ec4c858ca26c4ddf6315b26f9447831cf4403d82e9672482e53f8
|
Provenance
The following attestation bundles were made for kavenio_youtube_transcribe-0.1.0-py3-none-any.whl:
Publisher:
release.yml on kaveniohq/youtube-transcribe
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kavenio_youtube_transcribe-0.1.0-py3-none-any.whl -
Subject digest:
5c5b29116996799eabf249ffe062d660c7faa1bf14dc5a2171cf21079b91dcf7 - Sigstore transparency entry: 2248790515
- Sigstore integration time:
-
Permalink:
kaveniohq/youtube-transcribe@162f04fe0e37241b8d2d239741a3d1e0b4aa8290 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/kaveniohq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@162f04fe0e37241b8d2d239741a3d1e0b4aa8290 -
Trigger Event:
push
-
Statement type: