Build a YouTube Content Brain
Build a Python CLI that learns from YouTube videos and generates content.
Introduction
30 Second Summary
Ever notice how the best YouTube creators seem to have cracked a formula? Their titles grab you, their hooks pull you in, and their topics always land. Behind the scenes, those patterns are learnable.
In this project, you will build a Python command-line tool that ingests YouTube videos into a local knowledge base and uses Claude to generate optimized titles, descriptions, and tags that improve as the knowledge base grows.
What You'll Build
You paste a YouTube URL into your terminal, and seconds later your tool has extracted the video's transcript, title, tags, and view count into a growing brain file. When you ask it to generate content for your next video, it draws on everything it has learned from the creators you fed it.
By the end of this project, you'll have:
- A CLI tool that pulls metadata and full transcripts from any YouTube video with a single command.
- A persistent knowledge base that gets smarter every time you feed it a new video. Ask for title suggestions after ingesting 3-5 successful videos and compare the dramatically better output to what you got with zero context.
- A working AI content generation pipeline that connects Claude to real data, proving how grounded prompts outperform generic ones.
- Secret Mission: Add a pattern analysis command that identifies title formulas, common hooks, and optimal content themes across your entire knowledge base.
Are there any prerequisites?
None. This guide walks you through installing Python, setting up free API keys, and everything else from scratch. If you can open a terminal, you are ready to start.
Before We Start
You are about to build a Python command-line tool that learns from YouTube videos and generates increasingly better content suggestions. The tool connects to two APIs: one to pull video data from YouTube, and another to ask Claude for content ideas based on what it has learned.
Before you can start building, you need Python on your machine, a project folder with the right packages installed, and API keys that let your code talk to YouTube and Claude.
In this step, get ready to:
- Confirm Python 3.9+ is installed on your machine.
- Create a project folder and install your Python packages.
- Get API keys for YouTube Data API and Claude.
Check your Python installation
Your project needs Python version 3.9 or higher to run the packages you will install.
- Open your terminal by pressing Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Terminal (macOS) or Command Prompt (Windows) and press Enter to open it.
- Check your Python version by running this command:
python3 --version
You should see a version number printed, like Python 3.11.4.
✔️ I see version 3.9 or higher
Your Python version is ready. Move on to the next substep.
ⓧ I see an older version
You have Python installed but need a newer version. macOS often ships with an older Python that shadows newer installs.
- Download Python 3.11 or newer from python.org/downloads.
- Run the installer and follow the prompts.
- Close and reopen your terminal, then run python3 --version again to confirm the new version appears.
macOS default Python
macOS sometimes keeps an older system Python on the path. If python3 --version still shows an old version after installing, try running python3.11 --version (replacing 3.11 with whatever you installed). If that works, use python3.11 instead of python3 throughout this project.
ⓧ Command not found
Python is not installed on your machine yet.
- Download Python 3.11 or newer from python.org/downloads.
- Run the installer. On Windows, check the box that says Add Python to PATH before clicking Install Now.
- Close and reopen your terminal, then run python3 --version to confirm it prints a version number.
Create your project folder and install packages
Your project needs a dedicated folder on your Desktop and three Python packages that handle YouTube data, transcripts, and Claude.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir youtube-brain
cd youtube-brain
- Confirm the folder exists by running:
ls
You should see an empty directory with no output. Your terminal prompt now shows you are inside youtube-brain.
- Install the three project packages by running this command:
pip install youtube-transcript-api google-api-python-client anthropic
You will see pip downloading and installing each package. This may take 30 seconds to a minute.
Seeing permission errors or pip not found?
- If you see a permissions error, try adding --user to the end of the install command.
- If pip is not found, try pip3 instead. On some systems, pip for Python 3 is named pip3.
- help me fix my pip install issue
- Verify the packages installed correctly by running this command:
python3 -c "from youtube_transcript_api import YouTubeTranscriptApi; print('OK')"
You should see OK printed to the terminal. This confirms the packages are installed and importable.
Seeing a ModuleNotFoundError?
- Make sure you ran the pip install command in the same terminal session. If you opened a new terminal, run the install again.
- If you used python3.11 for the version check, use python3.11 -c here too, and install packages with python3.11 -m pip install.
- help me fix my ModuleNotFoundError
Set up your API keys
Your tool needs two API keys: one for fetching YouTube video data, and one for asking Claude to generate content suggestions.
You will get both keys now, then store them in a .env file so your code can read them.
Get your YouTube Data API key
The YouTube Data API lets your code fetch video titles, descriptions, tags, and view counts. It requires an API key from Google Cloud Console.
- Open console.cloud.google.com in your browser and sign in with a Google account.
- Click Select a project at the top of the page, then click New Project.
- Name your project youtube-brain and click Create.
- Once the project is created, make sure it is selected in the project dropdown at the top.
- Open the API Library by navigating to APIs & Services in the left sidebar, then clicking Library.
- Search for YouTube Data API v3 in the search bar.
- Click the YouTube Data API v3 result, then click Enable.
- After the API is enabled, click Create Credentials at the top of the page.
- Select API key from the menu.
- Your new API key appears in a dialog. Copy it and save it somewhere temporarily (a text file or notes app).
What is the YouTube Data API?
The YouTube Data API v3 lets your code read public video information: titles, descriptions, tags, view counts, and channel names. It uses a simple API key for authentication because you are only reading public data, not accessing anyone's private account.
The free tier gives you 10,000 quota units per day. Each video lookup costs 1 unit, so you can look up thousands of videos without spending anything.
Get your Claude API key
The Claude API from Anthropic is what your tool uses to generate content suggestions. You need an API key from the Anthropic console.
- Open console.anthropic.com in your browser.
- Sign up for a new account (or sign in if you already have one). You can continue with Google or email.
- Once signed in, navigate to the API Keys section in the console.
- Click Create Key to generate a new API key.
- Copy the key immediately and save it alongside your YouTube key. You will not be able to see it again after closing the dialog.
Is the Claude API free?
Anthropic provides free credits when you sign up. Each generation in this project uses a small number of tokens, costing fractions of a cent. You will stay well within free credit limits for this entire project.
Create your .env file
Now you will store both keys in a file your code can read. The .env file keeps secrets out of your source code.
- Open Cursor by pressing Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Cursor and press Enter to open it.
- In Cursor, click File in the top menu bar.
- Click Open Folder.
- Navigate to your Desktop, select the youtube-brain folder, and click Open.
- Create a new file by clicking File then New File.
- Save the file immediately with Cmd+S (macOS) or Ctrl+S (Windows) and name it .env.
- Paste the following into .env, replacing the placeholder values with your actual keys:
YOUTUBE_API_KEY=your-youtube-api-key-here
ANTHROPIC_API_KEY=your-anthropic-api-key-here
- Replace your-youtube-api-key-here with the YouTube API key you copied from Google Cloud Console.
- Replace your-anthropic-api-key-here with the Claude API key you copied from the Anthropic console.
- Save the file with Cmd+S (macOS) or Ctrl+S (Windows).
Why a .env file?
A .env file stores sensitive values like API keys separately from your code. Your Python script reads from this file at runtime. This way, you never accidentally share your keys if you push code to GitHub.
Before you run anything, predict: do you think the import verification from earlier will still work in a new terminal opened from Cursor?
- Open Cursor's built-in terminal by pressing Ctrl+` (backtick key, same shortcut on macOS and Windows).
- Verify everything is working by running this command:
python3 -c "from youtube_transcript_api import YouTubeTranscriptApi; print('OK')"
You should see OK printed. This confirms your packages are accessible from Cursor's terminal and you are ready to start building.
Terminal says command not found or ModuleNotFoundError?
- Make sure Cursor's terminal is open inside the youtube-brain folder. Check the prompt or run pwd to verify.
- If the packages are not found, run the pip install command again in this terminal.
- help me get my Cursor terminal working with my Python packages
Your environment is ready. You have Python, your packages, and both API keys stored safely. Next up, you will write the code that fetches your first YouTube video.
Fetch Your First Video
Your environment is set up with API keys and packages ready to go. Now you need to prove that your code can actually talk to YouTube and pull back real data.
In this step, you will build a Python script that takes any YouTube URL, extracts the video ID, fetches its metadata and transcript, and prints everything to your terminal. This is the foundation every future feature builds on.
In this step, get ready to:
- Write a configuration loader that reads API keys from your .env file.
- Build functions that fetch video metadata and transcripts from YouTube.
- Create a CLI command that ingests a video and prints its data to the terminal.
Create the script with imports and configuration
Your script needs to load the API keys you stored in .env before it can call any external service. You will write a small config loader that reads the file line-by-line and extracts key-value pairs.
- Create a new file called youtube_brain.py in your project folder and paste the following code:
import argparse
import json
import os
import re
from datetime import datetime
from anthropic import Anthropic
from googleapiclient.discovery import build
from youtube_transcript_api import YouTubeTranscriptApi
# --- Configuration ---
def load_api_keys():
"""Load API keys from .env file."""
keys = {}
env_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env")
if os.path.exists(env_path):
with open(env_path, "r") as f:
for line in f:
line = line.strip()
if "=" in line and not line.startswith("#"):
key, value = line.split("=", 1)
keys[key.strip()] = value.strip()
return keys
KEYS = load_api_keys()
YOUTUBE_API_KEY = KEYS.get("YOUTUBE_API_KEY", "")
ANTHROPIC_API_KEY = KEYS.get("ANTHROPIC_API_KEY", "")
KNOWLEDGE_BASE_FILE = "knowledge_base.json"
What does this code do?
- The imports bring in everything you need: argparse for the CLI, google-api-python-client for YouTube metadata, youtube-transcript-api for transcripts, and anthropic for Claude.
- The load_api_keys() function reads your .env file and splits each line at the = sign. It skips comments (lines starting with #).
- The module-level constants run load_api_keys() immediately when the script is imported, making your keys available everywhere in the file.
- Save youtube_brain.py.
- Verify the imports work and your .env file loads correctly by running this command:
python3 -c "from youtube_brain import YOUTUBE_API_KEY; print('Key loaded:', len(YOUTUBE_API_KEY), 'characters')"
You should see something like Key loaded: 39 characters printed. The exact number depends on your API key length.
Seeing an import error?
- If you see ModuleNotFoundError, confirm you installed the packages with pip install youtube-transcript-api google-api-python-client anthropic in the same Python environment.
- If you see Key loaded: 0 characters, check that your .env file is in the same folder as youtube_brain.py and that it contains YOUTUBE_API_KEY=your-actual-key with no spaces around the =.
Help me debug my youtube_brain.py import or .env loading issue.
Add the YouTube data functions
YouTube URLs come in several formats: youtube.com/watch?v=..., youtu.be/..., and youtube.com/embed/.... Your first function needs to handle all of these and extract the 11-character video ID.
- In youtube_brain.py, add the following code below your KNOWLEDGE_BASE_FILE line:
# --- YouTube Functions ---
def extract_video_id(url):
"""Extract video ID from a YouTube URL."""
patterns = [
r"(?:v=|\/v\/|youtu\.be\/|\/embed\/)([a-zA-Z0-9_-]{11})",
]
for pattern in patterns:
match = re.search(pattern, url)
if match:
return match.group(1)
return url
What does this code do?
The regex pattern matches the 11-character video ID from any common YouTube URL format. If no pattern matches, it assumes the input is already a raw video ID and returns it as-is.
- Next, add the two functions that call external APIs. Paste this code directly below extract_video_id:
def fetch_video_metadata(video_id):
"""Fetch video metadata from YouTube Data API."""
youtube = build("youtube", "v3", developerKey=YOUTUBE_API_KEY)
request = youtube.videos().list(
part="snippet,statistics",
id=video_id
)
response = request.execute()
if not response["items"]:
raise ValueError(f"No video found with ID: {video_id}")
item = response["items"][0]
snippet = item["snippet"]
statistics = item["statistics"]
return {
"title": snippet.get("title", ""),
"description": snippet.get("description", ""),
"tags": snippet.get("tags", []),
"view_count": int(statistics.get("viewCount", 0)),
"like_count": int(statistics.get("likeCount", 0)),
"channel_title": snippet.get("channelTitle", ""),
}
def fetch_transcript(video_id):
"""Fetch video transcript using youtube-transcript-api."""
ytt_api = YouTubeTranscriptApi()
transcript = ytt_api.fetch(video_id, languages=["en"])
full_text = " ".join([snippet.text for snippet in transcript])
return full_text
What does this code do?
- The fetch_video_metadata function calls the YouTube Data API to get the video's title, description, tags, view count, like count, and channel name.
- The fetch_transcript function uses the youtube-transcript-api library to grab the publicly available transcript. It joins all the text snippets into a single string.
- Unlike the YouTube Data API captions endpoint (which requires OAuth), this library can fetch transcripts from any public video without the video owner's permission.
- Save youtube_brain.py.
- Verify the URL parser works by running:
python3 -c "from youtube_brain import extract_video_id; print(extract_video_id('https://www.youtube.com/watch?v=dQw4w9WgXcQ'))"
You should see dQw4w9WgXcQ printed. That confirms the regex correctly extracts the video ID from a full URL.
Seeing something other than the video ID?
- If you see the full URL printed back, check that your extract_video_id function has the regex pattern copied exactly. The backslashes and escape sequences matter.
- If you see a syntax error, confirm there are no stray characters or missing quotes in the function.
Help me debug my extract_video_id function.
Build the CLI entry point
The functions are ready, but you have no way to call them from the terminal yet. Python's argparse module lets you define named commands (like ingest) that accept arguments.
- Add the CLI commands below your fetch_transcript function in youtube_brain.py:
# --- CLI Commands ---
def cmd_ingest(args):
"""Ingest a YouTube video into the knowledge base."""
video_id = extract_video_id(args.url)
print(f"Fetching video: {video_id}...")
metadata = fetch_video_metadata(video_id)
print(f"Title: {metadata['title']}")
print(f"Channel: {metadata['channel_title']}")
print(f"Views: {metadata['view_count']:,}")
print(f"Tags: {', '.join(metadata['tags'][:5])}")
print("Fetching transcript...")
transcript = fetch_transcript(video_id)
print(f"Transcript: {transcript[:200]}...")
What does this code do?
The cmd_ingest function orchestrates the full flow: extract the video ID from the URL, fetch metadata, fetch the transcript, and print a summary of everything to the terminal. It uses args.url which argparse will populate from the command line argument.
- Now add the main() function that wires up argparse. Paste this below cmd_ingest:
def main():
parser = argparse.ArgumentParser(description="YouTube Content Brain")
subparsers = parser.add_subparsers(dest="command", help="Available commands")
ingest_parser = subparsers.add_parser("ingest", help="Ingest a YouTube video")
ingest_parser.add_argument("url", help="YouTube video URL or ID")
args = parser.parse_args()
if args.command == "ingest":
cmd_ingest(args)
else:
parser.print_help()
if __name__ == "__main__":
main()
What does this code do?
- The argparse subparsers let you add multiple commands (like ingest, generate, status) to the same script. You will add more commands in later steps.
- The if __name__ == "__main__" guard ensures main() only runs when you execute the script directly, not when you import it.
- Save youtube_brain.py.
Test with a real video
Pick a YouTube video from a creator you follow. You need the full URL from your browser's address bar.
- Before you run the command below, predict: what do you expect the output to contain?
- Run the ingest command with a real YouTube URL by running:
python3 youtube_brain.py ingest "https://www.youtube.com/watch?v=VIDEO_ID_HERE"
Replace the URL
Replace the URL above with an actual YouTube video link from your browser. Pick a video that has English subtitles available for the transcript to work.
You should see the video's title, channel name, view count, first few tags, and the first 200 characters of the transcript printed to your terminal.
Seeing an error instead of video data?
- If you see HttpError 400 or HttpError 403, your YouTube Data API key may be invalid or the API is not enabled. Go back to Google Cloud Console, confirm the YouTube Data API v3 is enabled, and check the key is correct in your .env file.
- If you see a transcript error, the video may not have English subtitles. Try a different video from a major English-language creator.
- If you see No video found with ID, make sure you wrapped the URL in quotes. Without quotes, your terminal may cut off the URL at the & character.
Help me debug my youtube_brain.py ingest command.
✔️ Awesome, I've got everything!
Great. Double check you have saved youtube_brain.py and that running the ingest command prints real video data.
ⓧ I'd like to double check the full code
Your youtube_brain.py file should contain these sections in order. Scroll up and confirm each is present:
- Imports (lines 1-9): argparse, json, os, re, datetime, plus the three third-party imports.
- Configuration section: load_api_keys() function and the four module-level constants (KEYS, YOUTUBE_API_KEY, ANTHROPIC_API_KEY, KNOWLEDGE_BASE_FILE).
- YouTube Functions section: extract_video_id(), fetch_video_metadata(), fetch_transcript().
- CLI Commands section: cmd_ingest(), main(), and the if __name__ == "__main__" guard.
You have real YouTube data flowing into your terminal. Next up, you will ask Claude to generate content suggestions and see what it produces with zero context.
Ask Claude Without Context
In the last step, you pulled real video data from YouTube and saw it printed in your terminal. Now it's time to bring in the AI side of your tool.
Claude is the AI model that will power your content suggestions. But before you feed it any knowledge base, you need to see what it produces with zero context. This establishes a baseline you can compare against later.
In this step, get ready to:
- Add a content generation function that calls Claude.
- Wire up a generate CLI command with a --topic flag.
- Run it and observe the generic, context-free output.
Write the content generation function
The generate_content function is the bridge between your knowledge base and Claude. It builds a prompt from whatever context is available and sends it to Claude's API.
- In youtube_brain.py, find the # --- CLI Commands --- comment. Add a new section header and the first part of the generation function above it:
# --- Claude Functions ---
def generate_content(topic, knowledge_base):
"""Generate content suggestions using Claude."""
client = Anthropic(api_key=ANTHROPIC_API_KEY)
if knowledge_base:
context = "Here are videos from successful YouTube creators:\n\n"
for video in knowledge_base:
context += f"Title: {video['title']}\n"
context += f"Channel: {video['channel_title']}\n"
context += f"Views: {video['view_count']:,}\n"
context += f"Tags: {', '.join(video['tags'][:10])}\n"
context += f"Transcript snippet: {video['transcript'][:500]}\n"
context += "---\n"
system_prompt = (
"You are a YouTube content strategist. You have access to a knowledge base "
"of successful videos. Analyze the patterns in their titles, hooks, descriptions, "
"and topics. When generating suggestions, draw directly from these patterns. "
"Be specific about which patterns you are applying.\n\n"
f"{context}"
)
else:
system_prompt = (
"You are a YouTube content strategist. Generate a title and description "
"for a YouTube video. Be helpful but you have no specific data to draw from."
)
What does this code do?
This function takes two arguments: a topic and a knowledge base (which can be empty). It builds a different system prompt depending on whether context exists.
- If the knowledge base has videos, it formats them into a detailed context string for Claude to analyze.
- If the knowledge base is empty (which it will be right now), Claude gets a generic prompt with no real data to draw from.
- Add the API call directly below the code you just pasted (still inside the same function):
message = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system=system_prompt,
messages=[
{
"role": "user",
"content": (
f"Generate a YouTube title, description (2-3 sentences), and 5 tags "
f"for a video about: {topic}"
),
}
],
)
return message.content[0].text
What does the API call do?
- client.messages.create sends the request to Claude's API with the system prompt and your user message.
- model="claude-sonnet-4-6" specifies the Claude model. It balances cost and quality well for generating content suggestions.
- The function returns just the text of Claude's response.
- Save youtube_brain.py.
- Confirm there are no syntax errors by running:
python3 youtube_brain.py --help
You should see the help output listing your ingest command. If you see a SyntaxError, double-check the indentation inside your new function.
Seeing a SyntaxError?
- Make sure the message = client.messages.create(...) block is indented one level inside the function (4 spaces from the left edge).
- Check that the # --- Claude Functions --- section is placed between the YouTube functions and the CLI commands section, not inside another function.
- help me fix a SyntaxError in my generate_content function
Add the generate command to the CLI
The function exists, but there's no way to call it from the terminal yet. You need a CLI command that accepts a topic and passes it to generate_content.
- In youtube_brain.py, find the cmd_ingest function. Add a new cmd_generate function below it (before the main() function):
def cmd_generate(args):
"""Generate content suggestions using Claude."""
kb = []
print(f"Knowledge base: {len(kb)} videos")
print(f"Generating suggestions for: {args.topic}\n")
result = generate_content(args.topic, kb)
print(result)
Why is the knowledge base hardcoded as empty?
kb = [] passes an empty list to generate_content. This triggers the else branch, giving Claude no context. You have not built the knowledge base persistence yet. That comes in the next step.
Now you need to register this command with argparse so the CLI knows about it.
- Inside the main() function, find these lines:
ingest_parser = subparsers.add_parser("ingest", help="Ingest a YouTube video")
ingest_parser.add_argument("url", help="YouTube video URL or ID")
args = parser.parse_args()
- Add the generate subparser between the ingest_parser block and args = parser.parse_args(), so the section looks like this:
ingest_parser = subparsers.add_parser("ingest", help="Ingest a YouTube video")
ingest_parser.add_argument("url", help="YouTube video URL or ID")
generate_parser = subparsers.add_parser("generate", help="Generate content suggestions")
generate_parser.add_argument("--topic", required=True, help="Topic for your video")
args = parser.parse_args()
- Finally, find the command routing at the bottom of main():
if args.command == "ingest":
cmd_ingest(args)
else:
parser.print_help()
- Add the elif for the generate command, so it looks like this:
if args.command == "ingest":
cmd_ingest(args)
elif args.command == "generate":
cmd_generate(args)
else:
parser.print_help()
- Save youtube_brain.py.
Not sure where each piece goes?
- cmd_generate goes after cmd_ingest but before def main():.
- The generate_parser lines go inside main(), right after the ingest_parser lines.
- help me figure out where to place cmd_generate and the argparse code in my file
Run the generate command and observe the output
Your generate command is wired up. Before you run it, think about what you expect Claude to produce when it has absolutely no knowledge of any YouTube channel, style, or pattern.
What kind of title do you think Claude will suggest for your topic? Do you think it will be specific to your style, or could it apply to any channel?
- Run the generate command with a topic you actually care about:
python3 youtube_brain.py generate --topic "how to learn Python fast"
Pick a topic that matters to you
Replace "how to learn Python fast" with a topic you would actually make a video about. You will compare this output to what the brain produces later, so picking something real makes the comparison more meaningful.
You will see output like Knowledge base: 0 videos followed by a title, description, and tags from Claude. Read the suggestions carefully. They are correct and grammatically fine. But they are generic. They could apply to any channel. There is nothing specific to any creator's style or pattern.
That is the gap. This is exactly what the knowledge base will fix.
- Copy the output from your terminal and save it somewhere (a notes app, a text file, or just a comment at the bottom of your script). You will compare it to the knowledge-base-powered output in Step 5.
Why is generic output a problem?
A title like "Master Python: The Ultimate Beginner's Guide" is technically fine. But it does not reflect any specific creator's voice, format, or audience. It would not stand out in a feed full of similar videos.
The best YouTube titles follow patterns proven by real data. In the next steps, you will feed the brain videos from creators you admire, and the suggestions will shift to match what actually works.
Seeing an AuthenticationError?
- Check that your .env file has your real Anthropic API key (not the placeholder text).
- Make sure there are no spaces around the = sign in ANTHROPIC_API_KEY=sk-....
- Verify your key is still active at console.anthropic.com.
- help me fix an authentication error when calling the Claude API
✔️ Awesome, I've got everything!
Great. Double-check you have saved youtube_brain.py and that you have copied your generic output somewhere for later comparison.
ⓧ I'd like to double check the full code
Here is the full youtube_brain.py at this point. Your file has grown to include the Claude Functions section, cmd_generate, and the updated argparse. Scroll through and confirm each section is present in order:
- Imports and Configuration (unchanged from before).
- # --- YouTube Functions --- section with extract_video_id, fetch_video_metadata, and fetch_transcript.
- # --- Claude Functions --- section with generate_content (the new function you added).
- # --- CLI Commands --- section with cmd_ingest and cmd_generate.
- main() with both ingest_parser and generate_parser, plus the if/elif/else routing.
You have just seen the ceiling of what an LLM produces without context. The suggestions are polished but forgettable. Next up, you will build the knowledge base that gives Claude real data to learn from.
Build the Knowledge Base
In Step 3, you experienced what Claude produces with zero context. The output was generic and forgettable.
That generic output proves Claude needs real data to draw from. In this step, you will build a persistent JSON knowledge base that stores video data and grows over time. Every video you feed it makes Claude smarter.
In this step, get ready to:
- Create functions that load and save your knowledge base to a JSON file.
- Update the ingest command to persist video data instead of just printing it.
- Add a status command that reports how many videos are stored.
Add the knowledge base functions
Your knowledge base is a simple knowledge_base.json file that stores an array of video objects. You need two helper functions: one to load the file, and one to save back to it.
- In youtube_brain.py, find the comment that says # --- Claude Functions ---.
- Add the following code directly above that comment, creating a new section for the knowledge base:
# --- Knowledge Base Functions ---
def load_knowledge_base():
"""Load the knowledge base from JSON file."""
if os.path.exists(KNOWLEDGE_BASE_FILE):
with open(KNOWLEDGE_BASE_FILE, "r") as f:
return json.load(f)
return []
def save_knowledge_base(data):
"""Save the knowledge base to JSON file."""
with open(KNOWLEDGE_BASE_FILE, "w") as f:
json.dump(data, f, indent=2)
What does this code do?
- load_knowledge_base() checks if knowledge_base.json exists on disk. If it does, the function reads and returns its contents as a Python list. If not, it returns an empty list so the rest of your code can work without crashing.
- save_knowledge_base() writes the full list back to the JSON file with indent=2 for readability. You can open the file anytime to see exactly what is stored.
- Save youtube_brain.py.
These functions are not called anywhere yet. The next chunk wires them into the ingest command.
Update the ingest command to save video data
Right now, cmd_ingest fetches video data and prints it to the terminal. The data disappears as soon as you close the terminal. You need it to persist in your knowledge base file.
- In youtube_brain.py, scroll to the cmd_ingest function.
- Find the last line of the function, which currently reads:
print(f"Transcript: {transcript[:200]}...")
- Add the following code directly below that line, still inside the cmd_ingest function:
# Save to knowledge base
kb = load_knowledge_base()
entry = {
"video_id": video_id,
"title": metadata["title"],
"description": metadata["description"],
"tags": metadata["tags"],
"view_count": metadata["view_count"],
"like_count": metadata["like_count"],
"channel_title": metadata["channel_title"],
"transcript": transcript[:2000],
"ingested_at": datetime.now().isoformat(),
}
kb.append(entry)
save_knowledge_base(kb)
print(f"\nSaved to knowledge base. Total videos: {len(kb)}")
What does this code do?
- It loads whatever is already in the knowledge base (or an empty list if this is the first video).
- It builds an entry dictionary with all the useful video data. The transcript is capped at 2000 characters to keep the file manageable.
- It appends the new entry and writes the entire list back to disk. Each time you ingest, the file grows by one video.
You also need to update cmd_generate so it reads from the knowledge base file instead of using an empty list.
- In the cmd_generate function, find this line:
kb = []
- Replace it with:
kb = load_knowledge_base()
- Save youtube_brain.py.
- Test the updated ingest command by running it with a YouTube video URL from a creator you follow:
python3 youtube_brain.py ingest [[VIDEO_URL="a YouTube video URL from a creator you follow"]]
You should see the same metadata and transcript output as before, plus a new final line: Saved to knowledge base. Total videos: 1.
- Confirm the JSON file was created by running:
ls
You should see knowledge_base.json listed alongside youtube_brain.py and .env.
Not seeing the saved message?
- Make sure the new save code is indented inside the cmd_ingest function (4 spaces). If it is at the top level, Python runs it as a standalone block instead of part of the function.
- Check that the # --- Knowledge Base Functions --- section with load_knowledge_base and save_knowledge_base appears above the # --- Claude Functions --- section. The ingest function calls them, so they must be defined first.
Help me debug my ingest command not saving to the knowledge base.
Add a status command
You need a quick way to check what is in your knowledge base without opening the JSON file manually. A status command gives you that at a glance.
- In youtube_brain.py, find the cmd_generate function.
- Add the following new function directly below cmd_generate:
def cmd_status(args):
"""Show knowledge base status."""
kb = load_knowledge_base()
print(f"{len(kb)} videos in knowledge base")
if kb:
print("\nVideos:")
for video in kb:
print(f" - {video['title']} ({video['view_count']:,} views)")
What does this code do?
It loads the knowledge base and prints the total count. If videos exist, it lists each one by title and view count so you can see at a glance what you have ingested.
Now you need to register this command in the CLI so argparse knows about it.
- In the main function, find this line:
generate_parser.add_argument("--topic", required=True, help="Topic for your video")
- Add this line directly below it to register the status subcommand:
subparsers.add_parser("status", help="Show knowledge base status")
- Still in the main function, find the command dispatch section. Locate this line:
elif args.command == "generate":
cmd_generate(args)
- Add the status dispatch directly below it, before the else block:
elif args.command == "status":
cmd_status(args)
- Save youtube_brain.py.
- Test the status command by running:
python3 youtube_brain.py status
You should see 1 videos in knowledge base followed by the title and view count of the video you ingested earlier.
Seeing 0 videos in knowledge base?
- Make sure you ran the ingest command successfully in the previous substep. If it did not print the Saved message, the JSON file may be empty or missing.
- Check that load_knowledge_base uses the same KNOWLEDGE_BASE_FILE constant as save_knowledge_base. Both should reference knowledge_base.json.
Help me debug why my status command shows 0 videos.
Now feed your brain more data. Before you run the next commands, think about this: what do you expect the count to show after ingesting two more videos?
- Ingest a second video from a different creator by running:
python3 youtube_brain.py ingest [[VIDEO_URL_2="a second YouTube video URL"]]
- Ingest a third video by running:
python3 youtube_brain.py ingest [[VIDEO_URL_3="a third YouTube video URL"]]
- Run the status command one more time:
python3 youtube_brain.py status
You should see 3 videos in knowledge base followed by all three titles and their view counts. Each ingest made the brain grow.
✔️ Awesome, I've got everything!
Great. Double check you have saved youtube_brain.py and that knowledge_base.json exists in your project folder.
ⓧ I'd like to double check the full code
Scroll through your youtube_brain.py and confirm these sections appear in order:
- Imports and the # --- Configuration --- section with load_api_keys and the key constants.
- # --- YouTube Functions --- section with extract_video_id, fetch_video_metadata, and fetch_transcript.
- # --- Knowledge Base Functions --- section with load_knowledge_base and save_knowledge_base.
- # --- Claude Functions --- section with generate_content.
- # --- CLI Commands --- section with cmd_ingest (ending with the save logic), cmd_generate (using load_knowledge_base()), and cmd_status.
- The main function with ingest, generate, and status subparsers and their dispatch.
Your brain now has real data. Three videos worth of titles, transcripts, tags, and view counts sitting in a file on your machine. Next up, you will plug this knowledge base into Claude and see how dramatically the output improves.
Generate With the Brain
In Step 3, you asked Claude for content suggestions and got generic, forgettable output. That was the baseline. Now your knowledge base has 3 real videos in it, complete with titles, tags, view counts, and transcript snippets.
The generate_content function already knows how to use this data. When the knowledge base has entries, it feeds everything to Claude as context and instructs it to analyze patterns before generating. Time to see if it actually makes a difference.
In this step, get ready to:
- Run the generate command with your populated knowledge base.
- Compare the context-aware output to the generic output from Step 3.
- Feed the brain one more video and observe how the output shifts.
Understand how the knowledge base feeds into Claude
Your generate_content function already handles both scenarios: an empty knowledge base and a populated one. Let's trace exactly what happens now that you have 3 videos stored.
- In Cursor, open youtube_brain.py and scroll to the generate_content function.
- Find this block of code inside the if knowledge_base: branch:
if knowledge_base:
context = "Here are videos from successful YouTube creators:\n\n"
for video in knowledge_base:
context += f"Title: {video['title']}\n"
context += f"Channel: {video['channel_title']}\n"
context += f"Views: {video['view_count']:,}\n"
context += f"Tags: {', '.join(video['tags'][:10])}\n"
context += f"Transcript snippet: {video['transcript'][:500]}\n"
context += "---\n"
What does this code do?
When the knowledge base has videos in it, this loop builds a context string containing every video's title, channel, view count, top 10 tags, and the first 500 characters of transcript.
That context string gets injected into Claude's system prompt, so Claude can see the actual patterns in successful videos before generating suggestions for you. The more videos you feed it, the richer that context becomes.
- Now find the system prompt that uses this context:
system_prompt = (
"You are a YouTube content strategist. You have access to a knowledge base "
"of successful videos. Analyze the patterns in their titles, hooks, descriptions, "
"and topics. When generating suggestions, draw directly from these patterns. "
"Be specific about which patterns you are applying.\n\n"
f"{context}"
)
Why does this prompt work better than the generic one?
In Step 3, Claude's system prompt said "you have no specific data to draw from." Now it says "analyze the patterns" and "be specific about which patterns you are applying." The instruction plus the actual video data forces Claude to ground its suggestions in real examples instead of guessing.
Run generate and compare to Step 3
Your knowledge base has 3 videos. Your generate_content function builds context from all of them. Time to see the difference.
- Before you run this, think back to the generic output from Step 3. Do you think the output will be noticeably different now that Claude has 3 real videos to draw from?
- Run the generate command with the same topic you used in Step 3:
python3 youtube_brain.py generate --topic "your topic from Step 3"
The output now references specific patterns, title structures, and stylistic choices drawn from your ingested videos. Compare it to the generic output you saved from Step 3.
What should I see?
Instead of vague, one-size-fits-all suggestions, Claude now names specific patterns it observed in your videos. You might see it reference a title formula like "How I [action] in [timeframe]" that it noticed across your ingested videos, or suggest tags that mirror the ones successful creators used.
The suggestions feel tailored because they ARE tailored. Claude is drawing on real data, not inventing generic advice.
Output still looks generic?
- Run python3 youtube_brain.py status to confirm you have 3 videos in the knowledge base. If it shows 0, your previous ingest commands may not have saved correctly.
- Check that knowledge_base.json exists in the same folder as youtube_brain.py. The function looks for the file in the current working directory.
- Make sure your .env file has a valid ANTHROPIC_API_KEY. An invalid key produces an authentication error, not generic output.
Why is my generate output still generic even with videos in the knowledge base?
Feed the brain one more video
The brain gets smarter with every video you add. Let's prove it by ingesting a 4th video and watching the output shift.
- Pick one more YouTube video from a creator in your niche. Choose one with a different style or angle than your first three.
- Ingest it by running:
python3 youtube_brain.py ingest VIDEO_URL
- You should see the video's title, channel, view count, and transcript snippet print to the terminal, followed by "Saved to knowledge base. Total videos: 4".
- Now run generate again with the same topic:
python3 youtube_brain.py generate --topic "your topic from Step 3"
The output subtly shifts to incorporate the new video's patterns. If the 4th video used a different title formula or covered the topic from a new angle, you'll see that reflected in Claude's suggestions.
Why does one more video matter?
Each video adds new data points to the system prompt. Claude sees a wider range of patterns and can make stronger recommendations about what works. This is the compounding effect: the tool gets better every time you use it.
Seeing a transcript error?
- Not all YouTube videos have transcripts available. If you see an error about transcripts, try a different video that has captions enabled.
- Videos in languages other than English may fail because the code requests English transcripts specifically. Choose a video with English captions.
Help me fix a transcript fetch error in my YouTube Brain tool.
- Confirm the brain's growth by running:
python3 youtube_brain.py status
You should see "4 videos in knowledge base" followed by a list of all your ingested videos with their view counts.
You now have a content tool that compounds in value. Every video you feed it makes the next suggestion sharper. Next up, you'll take on the Secret Mission and build a pattern analysis engine that surfaces the strategies behind what works.
Secret mission
Add a Pattern Analysis Command
Your brain can generate content, but can it tell you WHY certain videos succeed? Add a pattern analysis command that identifies title formulas, common hooks, and recurring themes across your entire knowledge base.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely on your local machine with free-tier API access. There are no ongoing costs unless you make additional API calls beyond the free credits provided on sign-up.
Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- YouTube Data API key (Google Cloud Console).
- Claude API key (console.anthropic.com).
- Local project files (youtube_brain.py, .env, knowledge_base.json).
- Python packages (youtube-transcript-api, google-api-python-client, anthropic).
Keep everything running
No action needed. Choose this if you plan to keep feeding videos into your knowledge base over time.
- Your API keys remain active and ready to use.
- Your knowledge_base.json stays on disk, growing with every video you ingest.
- The YouTube Data API free tier gives you 10,000 quota units per day at no cost.
- Claude API usage beyond your initial free credits is pay-per-use. Each generation in this project costs fractions of a cent.
Pause - I'll come back to this later
There are no running services to stop. Your JSON file and script stay on disk until you return.
- No running processes need to be shut down.
- Your knowledge_base.json persists with all your ingested video data.
- Your API keys remain valid. You can pick up where you left off any time.
Delete - I don't want to use this again
Remove all project resources and revoke your API keys so nothing lingers on your machine or in the cloud.
- Delete your YouTube Data API key by signing in to the Google Cloud Console.
- Open APIs & Services from the navigation menu, then select Credentials.
- Click the name of your API key, then click Delete.
- Delete your Claude API key by signing in to console.anthropic.com, navigating to your API keys page, selecting the key you created, and deleting it.
- Delete your local project files by running these commands in the terminal:
macOS
cd ~/Desktop
rm -rf youtube-brain
Windows
cd ~\Desktop
Remove-Item -Recurse -Force youtube-brain
- Uninstall the Python packages by running:
pip uninstall youtube-transcript-api google-api-python-client anthropic -y
Nice Work!
Nice Work!
You just built a Python CLI tool that turns YouTube videos into a growing knowledge base, then uses that knowledge to generate content suggestions that get better over time.
You've learned how to:
- Built a Python CLI that fetches YouTube video metadata and transcripts using two different REST APIs.
- Created a persistent JSON knowledge base that grows with every video you ingest.
- Connected Claude to your knowledge base with a system prompt that turns raw data into actionable content suggestions.
- Experienced the difference between a generic LLM response and one grounded in real data.
- Secret Mission: Built a pattern analysis engine that identifies title formulas and content themes across your entire knowledge base.
Ready to quiz yourself?