Claude-blog blog-notebooklm
git clone https://github.com/AgriciDaniel/claude-blog
T=$(mktemp -d) && git clone --depth=1 https://github.com/AgriciDaniel/claude-blog "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/blog-notebooklm" ~/.claude/skills/agricidaniel-claude-blog-blog-notebooklm && rm -rf "$T"
skills/blog-notebooklm/SKILL.mdBlog NotebookLM -- Source-Grounded Research from Your Documents
Query Google NotebookLM notebooks directly from Claude Code for citation-backed answers from Gemini. Each question opens a headless browser session, retrieves the answer exclusively from your uploaded documents, and closes. Responses are Tier 1 quality (user's own primary sources) -- zero hallucination risk.
Quick Reference
| Command | What it does |
|---|---|
| Query a notebook for source-grounded answers |
| Smart-discover notebook content before cataloging |
| List all notebooks in library |
| Add a notebook to library |
| Search notebooks by keyword |
| Remove a notebook from library |
| One-time Google authentication (browser visible) |
| Check authentication status |
| Clean browser state (preserves library) |
Prerequisites
- Google account with NotebookLM access
- Python 3.11+ (venv managed automatically by
)run.py - Google Chrome (installed automatically on first run via Patchright)
- One-time authentication setup (interactive Google login in visible browser)
Always Use run.py Wrapper
NEVER call scripts directly. ALWAYS use
:python3 scripts/run.py [script]
# CORRECT: python3 scripts/run.py auth_manager.py status python3 scripts/run.py ask_question.py --question "..." # WRONG -- fails without venv: python3 scripts/auth_manager.py status
The
run.py wrapper automatically creates .venv, installs dependencies,
sets up Chrome, and executes the target script.
Auth Check (Gate Pattern)
Before any query operation, check authentication:
python3 scripts/run.py auth_manager.py status
- If authenticated: proceed with the query
- If not authenticated: inform user and guide to setup:
"NotebookLM requires Google login. Run
to authenticate."/blog notebooklm setup - When called internally (from blog-write or blog-researcher): return silently with no error if not authenticated. Never block the writing workflow.
Setup Workflow
For
/blog notebooklm setup:
# Opens a visible browser for manual Google login (one-time) python3 scripts/run.py auth_manager.py setup
Tell the user: "A browser window will open. Please log in to your Google account." Authentication persists via browser profile + cookie injection (hybrid approach).
Other auth commands:
python3 scripts/run.py auth_manager.py status # Check auth python3 scripts/run.py auth_manager.py reauth # Re-authenticate python3 scripts/run.py auth_manager.py clear # Clear all auth data
Query Workflow
For
/blog notebooklm ask <question>:
Step 1: Check Auth
Run auth check (see gate pattern above). If not authenticated, guide to setup.
Step 2: Resolve Notebook
Determine which notebook to query:
- If
provided: use directly--notebook-url - If
provided: look up in library--notebook-id - If neither: use active notebook from library
- If no active notebook: show library and ask user to select
Step 3: Ask the Question
# Basic query (uses active notebook) python3 scripts/run.py ask_question.py --question "Your question here" # Query specific notebook by ID python3 scripts/run.py ask_question.py --question "..." --notebook-id notebook-id # Query by URL directly python3 scripts/run.py ask_question.py --question "..." --notebook-url "https://..." # JSON output (for internal/programmatic use) python3 scripts/run.py ask_question.py --question "..." --json # Show browser for debugging python3 scripts/run.py ask_question.py --question "..." --show-browser
Step 4: Analyze and Follow Up
Every response ends with a follow-up prompt. Required behavior:
- STOP -- do not immediately respond to the user
- ANALYZE -- compare the answer to the user's original request
- IDENTIFY GAPS -- determine if more information is needed
- ASK FOLLOW-UP -- if gaps exist, immediately ask a follow-up question
- REPEAT -- continue until information is complete
- SYNTHESIZE -- combine all answers before responding to the user
Smart Discovery Workflow
For
/blog notebooklm discover <url>:
When adding a notebook without knowing its content, query it first:
# Step 1: Discover content python3 scripts/run.py ask_question.py \ --question "What is the content of this notebook? What topics are covered? Provide a complete overview briefly and concisely" \ --notebook-url "<URL>" # Step 2: Add with discovered metadata python3 scripts/run.py notebook_manager.py add \ --url "<URL>" \ --name "<Based on content>" \ --description "<Based on content>" \ --topics "<Extracted topics>"
NEVER guess or use generic descriptions. Always discover or ask the user.
Library Management
# List all notebooks python3 scripts/run.py notebook_manager.py list # Add notebook (all params required -- discover or ask user!) python3 scripts/run.py notebook_manager.py add \ --url "https://notebooklm.google.com/notebook/..." \ --name "Descriptive Name" \ --description "What this notebook contains" \ --topics "topic1,topic2,topic3" # Search by keyword python3 scripts/run.py notebook_manager.py search --query "keyword" # Set active notebook python3 scripts/run.py notebook_manager.py activate --id notebook-id # Remove notebook python3 scripts/run.py notebook_manager.py remove --id notebook-id # Library statistics python3 scripts/run.py notebook_manager.py stats
Internal API (for blog-write / blog-researcher)
When invoked as a Task subagent from blog-write or blog-researcher:
Input (provided by calling skill):
: Research question relevant to the blog topicquestion
ornotebook_id
: Which notebook to querynotebook_url
: "internal" (signals graceful fallback mode)context
Process:
- Check auth status -- if not authenticated, return empty result silently
- Query the notebook with the research question
- Parse and return structured response
Output (returned to calling skill):
### NotebookLM Research - **Source:** [Notebook name] - **Question:** [What was asked] - **Answer:** [Source-grounded response from user's documents] - **Source Quality:** Tier 1 (user-uploaded primary documents)
Graceful fallback: If auth is missing or query fails, return immediately with no error. The calling workflow continues with WebSearch-based research. Never block blog-write or blog-rewrite because NotebookLM is unavailable.
Data Storage
All data stored inside the skill directory:
-- Notebook metadata and libraryscripts/data/library.json
-- Authentication statusscripts/data/auth_info.json
-- Chrome profile with cookiesscripts/data/browser_state/
Security: All data directories are gitignored. Never commit auth or browser state.
Error Handling
| Error | Resolution |
|---|---|
| Not authenticated | Run |
| ModuleNotFoundError | Always use wrapper |
| Browser crash | , then re-auth |
| Rate limit (50/day) | Wait until midnight PST or switch Google account |
| Notebook not found | Check with |
| Query timeout (120s) | Retry with simpler question or to debug |
| MCP unavailable (internal) | Return silently -- writing workflow uses WebSearch |
Limitations
- No session persistence (each question = new browser session)
- Rate limits on free Google accounts (50 queries/day)
- Manual upload required (user must add docs to NotebookLM web UI)
- Browser overhead (few seconds per question for launch + teardown)
- Local Claude Code only (not available in web UI)
Reference Documentation
Load on-demand -- do NOT load all at startup:
-- Full CLI commands, parameters, and workflow patternsreferences/commands.md
-- Error solutions, recovery procedures, debuggingreferences/troubleshooting.md