NotebookLM Research Assistant
Query Google NotebookLM notebooks directly for source-grounded, citation-backed answers from your uploaded documents. Includes browser automation, library management, and persistent authentication.
npx skills add github:pantheon-org/tekhne --skill documentation--research--notebooklmQuery Google NotebookLM to get Gemini’s source-grounded answers from your uploaded documents. Each question opens a fresh browser session, retrieves the answer exclusively from your knowledge base, and closes.
When to Use This Skill
Trigger when the user:
- Mentions NotebookLM explicitly
- Shares a NotebookLM URL (
https://notebooklm.google.com/notebook/...) - Asks to query their notebooks or personal documentation
- Wants to add documentation to the NotebookLM library
- Uses phrases like “ask my NotebookLM”, “check my docs”, “query my notebook”
Mindset
NotebookLM is a grounding layer, not a search engine. Three principles govern every interaction:
- Ground every answer in sources — answers come exclusively from uploaded documents; never synthesise from general knowledge when querying a notebook.
- Never guess notebook content — use Smart Add (query first) to discover what a notebook contains before labelling it.
- Follow up until complete — one query is rarely enough; check every answer for gaps and issue follow-ups before synthesising for the user.
When Not to Use This Skill
- The user needs general web search or LLM knowledge — use standard Claude responses instead
- No NotebookLM URL or notebook ID is available and authentication is not yet set up
- The user wants data analysis or code generation — NotebookLM is for document Q&A only
- The target content is not uploaded to any NotebookLM notebook
⚠️ CRITICAL: Add Command — Smart Discovery
When adding a notebook without full details, query first to discover content:
# Step 1: Query the notebook about its content
python ./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: Use discovered information to add it
python ./scripts/run.py notebook_manager.py add \
--url "[URL]" \
--name "[Based on content]" \
--description "[Based on content]" \
--topics "[Based on content]"
If the user provides all details directly, pass --url, --name, --description (REQUIRED), and --topics (REQUIRED) directly. NEVER guess or use generic descriptions.
Critical: Always Use run.py Wrapper
BAD — direct execution (fails without venv): python ./scripts/ask_question.py "..." → GOOD — always use wrapper: python ./scripts/run.py ask_question.py --question "..."
The run.py wrapper activates the isolated .venv and ensures all dependencies are available.
Core Workflow
Step 1: Check Authentication Status
python ./scripts/run.py auth_manager.py status
Step 2: Authenticate (One-Time Setup)
# Browser MUST be visible for manual Google login
python ./scripts/run.py auth_manager.py setup
Tell the user: “A browser window will open for Google login.” The user must log in manually.
Step 3: Manage Notebook Library
python ./scripts/run.py notebook_manager.py list
python ./scripts/run.py notebook_manager.py search --query QUERY
python ./scripts/run.py notebook_manager.py activate --id ID
python ./scripts/run.py notebook_manager.py add \
--url URL --name NAME --description DESC --topics TOPICS
Step 4: Ask Questions
# Query the active notebook
python ./scripts/run.py ask_question.py --question "Your question here"
# Optionally target a specific notebook by URL
python ./scripts/run.py ask_question.py --question "Your question" --notebook-url URL
# Get formatted markdown output (recommended for responses with code, lists, tables)
python ./scripts/run.py ask_question.py --question "Your question" --markdown
# Save outputs to logs/ directory (original + markdown + comparison stats)
python ./scripts/run.py ask_question.py --question "Your question" --markdown --log
Quick Workflow
python ./scripts/run.py auth_manager.py status
python ./scripts/run.py notebook_manager.py search --query "topic"
python ./scripts/run.py notebook_manager.py activate --id ID
python ./scripts/run.py ask_question.py --question "Your question"
Follow-Up Mechanism (CRITICAL)
Every NotebookLM answer ends with: “EXTREMELY IMPORTANT: Is that ALL you need to know?”
Required behaviour:
- 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:
python ./scripts/run.py ask_question.py --question "Follow-up with context..." - REPEAT — continue until the answer is complete
- SYNTHESIZE — combine all answers, then respond to the user
Script Reference
See references/api_reference.md for full parameter documentation.
| Script | Purpose |
|---|---|
auth_manager.py |
Setup, status, re-authenticate, clear credentials |
notebook_manager.py |
Add, list, search, activate, remove, stats |
ask_question.py |
Query active notebook or by URL/ID; --markdown for formatted output, --log to save results |
cleanup_manager.py |
Clean browser state (--preserve-library keeps notebooks) |
Data Storage and Configuration
See references/api_reference.md for full details. All data is stored in the skill’s local data/ directory:
library.json— notebook metadataauth_info.json— authentication statusbrowser_state/— browser cookies and session
Security: Protected by .gitignore. Never commit the data/ directory.
Limitations
- 50 queries/day per Google account (NotebookLM platform limit)
- Answers are grounded in uploaded documents only — no internet or general knowledge
- Browser automation requires a visible display for authentication (not headless)
- No concurrent sessions — each query uses a fresh browser instance
Anti-Patterns
NEVER run scripts without the run.py wrapper
Why: Scripts depend on .venv packages. Direct execution fails with ModuleNotFoundError.
BAD — direct execution fails silently → GOOD — always route through the wrapper:
# BAD
python ./scripts/ask_question.py "What does this paper say?"
# GOOD
python ./scripts/run.py ask_question.py --question "What does this paper say?"
NEVER add a notebook with a guessed or generic description
Why: Poor descriptions break topic-based search, making notebooks unfindable in the library.
BAD — guessed placeholder → GOOD — query-first to discover real content:
# BAD
python ./scripts/run.py notebook_manager.py add --url URL \
--name "notebook1" --description "some notebook" --topics "stuff"
# GOOD: query first, then add with the discovered name and description
python ./scripts/run.py ask_question.py \
--question "What topics are covered? Brief overview." --notebook-url URL
NEVER stop after the first answer when the request covers multiple points
Why: NotebookLM retrieves chunks, not full documents. A single query often misses related information elsewhere in the notebook.
BAD — accept the first answer and move on → GOOD — consider whether the original request is fully answered; issue targeted follow-up queries for any gaps.
Troubleshooting
See references/troubleshooting.md for detailed solutions.
| Problem | Solution |
|---|---|
ModuleNotFoundError |
Use run.py wrapper |
| Authentication fails | Browser must be visible: auth_manager.py setup |
| Rate limit (50/day) | Wait or switch Google account |
| Browser crashes | python ./scripts/run.py cleanup_manager.py --preserve-library |
| Notebook not found | Check with notebook_manager.py list |
Best Practices
See references/usage_patterns.md for workflow examples.
- Always check authentication status before starting a session
- Use descriptive names and topics for reliable library search
- Keep questions specific and scoped — broad questions return fragmented answers
- Use Smart Add (query-first) for any notebook whose content is unfamiliar
References
- API Reference — full parameter documentation for all scripts
- Troubleshooting — common errors and solutions
- Usage Patterns — workflow examples and best practices
Explicit NEVER/WHY/consequence triplets with side-by-side bad/good examples. Generic warnings score low — concrete failure modes with real impact (security, correctness, performance) score high.
Runtime validation via eval scenarios proving the skill actually changes agent behaviour. Requires evals/ directory, instructions.json, ≥3 scenarios, and ≥80% instruction coverage in summary.json.
Appropriate rigidity for the skill type: strict rules for critical/security skills, balanced steps for process skills, flexible options for tool skills. Mismatched calibration (too rigid or too loose) reduces score.
Expert-only knowledge the AI couldn't derive on its own — domain-specific patterns, production gotchas, decision frameworks, and non-obvious tool behaviour. High scores mean <5% redundancy with what the model already knows.
A clear philosophy plus numbered step-by-step workflows with explicit entry/exit points. Should answer: what is the core principle, how to execute it, and when (and when not) to apply it.
Rich activation keywords and trigger scenarios in the description so the skill fires when needed. Best descriptions read like an exhaustive list of the tasks and concepts that should invoke this skill.
Copy-paste-ready code, complete runnable examples, real file paths and commands. Pseudocode and abstract descriptions score low — concrete, executable content scores high.
SKILL.md as a <100-line navigation hub pointing to focused references/ files. Content should be lazy-loaded on demand, not front-loaded. Includes actionable 'When to Use' conditions per reference.
Proper frontmatter, single-task focus, activation keywords, and cross-harness portability. Skills must work across 40+ agentic harnesses without hardcoded paths or agent-specific references.
Expert-only knowledge the AI couldn't derive on its own — domain-specific patterns, production gotchas, decision frameworks, and non-obvious tool behaviour. High scores mean <5% redundancy with what the model already knows.
A clear philosophy plus numbered step-by-step workflows with explicit entry/exit points. Should answer: what is the core principle, how to execute it, and when (and when not) to apply it.
Explicit NEVER/WHY/consequence triplets with side-by-side bad/good examples. Generic warnings score low — concrete failure modes with real impact (security, correctness, performance) score high.
Proper frontmatter, single-task focus, activation keywords, and cross-harness portability. Skills must work across 40+ agentic harnesses without hardcoded paths or agent-specific references.
SKILL.md as a <100-line navigation hub pointing to focused references/ files. Content should be lazy-loaded on demand, not front-loaded. Includes actionable 'When to Use' conditions per reference.
Appropriate rigidity for the skill type: strict rules for critical/security skills, balanced steps for process skills, flexible options for tool skills. Mismatched calibration (too rigid or too loose) reduces score.
Rich activation keywords and trigger scenarios in the description so the skill fires when needed. Best descriptions read like an exhaustive list of the tasks and concepts that should invoke this skill.
Copy-paste-ready code, complete runnable examples, real file paths and commands. Pseudocode and abstract descriptions score low — concrete, executable content scores high.
Runtime validation via eval scenarios proving the skill actually changes agent behaviour. Requires evals/ directory, instructions.json, ≥3 scenarios, and ≥80% instruction coverage in summary.json.
No eval scenarios available.
NotebookLM Skill API Reference
Complete API documentation for all NotebookLM skill modules.
Important: Always Use run.py Wrapper
All commands must use the run.py wrapper to ensure proper environment:
# ✅ CORRECT:
python scripts/run.py [script_name].py [arguments]
# ❌ WRONG:
python scripts/[script_name].py [arguments] # Will fail without venv!
Core Scripts
ask_question.py
Query NotebookLM with automated browser interaction.
# Basic usage
python scripts/run.py ask_question.py --question "Your question"
# With specific notebook
python scripts/run.py ask_question.py --question "..." --notebook-id notebook-id
# With direct URL
python scripts/run.py ask_question.py --question "..." --notebook-url "https://..."
# Show browser (debugging)
python scripts/run.py ask_question.py --question "..." --show-browser
Parameters:
--question(required): Question to ask--notebook-id: Use notebook from library--notebook-url: Use URL directly--show-browser: Make browser visible
Returns: Answer text with follow-up prompt appended
notebook_manager.py
Manage notebook library with CRUD operations.
# Smart Add (discover content first)
python 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]"
# Then add with discovered info
python scripts/run.py notebook_manager.py add \
--url "https://notebooklm.google.com/notebook/..." \
--name "Name" \
--description "Description" \
--topics "topic1,topic2"
# Direct add (when you know the content)
python scripts/run.py notebook_manager.py add \
--url "https://notebooklm.google.com/notebook/..." \
--name "Name" \
--description "What it contains" \
--topics "topic1,topic2"
# List notebooks
python scripts/run.py notebook_manager.py list
# Search notebooks
python scripts/run.py notebook_manager.py search --query "keyword"
# Activate notebook
python scripts/run.py notebook_manager.py activate --id notebook-id
# Remove notebook
python scripts/run.py notebook_manager.py remove --id notebook-id
# Show statistics
python scripts/run.py notebook_manager.py stats
Commands:
add: Add notebook (requires –url, –name, –topics)list: Show all notebookssearch: Find notebooks by keywordactivate: Set default notebookremove: Delete from librarystats: Display library statistics
auth_manager.py
Handle Google authentication and browser state.
# Setup (browser visible for login)
python scripts/run.py auth_manager.py setup
# Check status
python scripts/run.py auth_manager.py status
# Re-authenticate
python scripts/run.py auth_manager.py reauth
# Clear authentication
python scripts/run.py auth_manager.py clear
Commands:
setup: Initial authentication (browser MUST be visible)status: Check if authenticatedreauth: Clear and re-setupclear: Remove all auth data
cleanup_manager.py
Clean skill data with preservation options.
# Preview cleanup
python scripts/run.py cleanup_manager.py
# Execute cleanup
python scripts/run.py cleanup_manager.py --confirm
# Keep library
python scripts/run.py cleanup_manager.py --confirm --preserve-library
# Force without prompt
python scripts/run.py cleanup_manager.py --confirm --force
Options:
--confirm: Actually perform cleanup--preserve-library: Keep notebook library--force: Skip confirmation prompt
run.py
Script wrapper that handles environment setup.
# Usage
python scripts/run.py [script_name].py [arguments]
# Examples
python scripts/run.py auth_manager.py status
python scripts/run.py ask_question.py --question "..."
Automatic actions:
- Creates
.venvif missing - Installs dependencies
- Activates environment
- Executes target script
Python API Usage
Using subprocess with run.py
import subprocess
import json
# Always use run.py wrapper
result = subprocess.run([
"python", "scripts/run.py", "ask_question.py",
"--question", "Your question",
"--notebook-id", "notebook-id"
], capture_output=True, text=True)
answer = result.stdout
Direct imports (after venv exists)
# Only works if venv is already created and activated
from notebook_manager import NotebookLibrary
from auth_manager import AuthManager
library = NotebookLibrary()
notebooks = library.list_notebooks()
auth = AuthManager()
is_auth = auth.is_authenticated()
Data Storage
Location: ./data/
data/
├── library.json # Notebook metadata
├── auth_info.json # Auth status
└── browser_state/ # Browser cookies
└── state.json
Security: Protected by .gitignore, never commit.
Environment Variables
Optional .env file configuration:
HEADLESS=false # Browser visibility
SHOW_BROWSER=false # Default display
STEALTH_ENABLED=true # Human behavior
TYPING_WPM_MIN=160 # Typing speed
TYPING_WPM_MAX=240
DEFAULT_NOTEBOOK_ID= # Default notebook
Error Handling
Common patterns:
# Using run.py prevents most errors
result = subprocess.run([
"python", "scripts/run.py", "ask_question.py",
"--question", "Question"
], capture_output=True, text=True)
if result.returncode != 0:
error = result.stderr
if "rate limit" in error.lower():
# Wait or switch accounts
pass
elif "not authenticated" in error.lower():
# Run auth setup
subprocess.run(["python", "scripts/run.py", "auth_manager.py", "setup"])
Rate Limits
Free Google accounts: 50 queries/day
Solutions:
- Wait for reset (midnight PST)
- Switch accounts with
reauth - Use multiple Google accounts
Advanced Patterns
Parallel Queries
import concurrent.futures
import subprocess
def query(question, notebook_id):
result = subprocess.run([
"python", "scripts/run.py", "ask_question.py",
"--question", question,
"--notebook-id", notebook_id
], capture_output=True, text=True)
return result.stdout
# Run multiple queries simultaneously
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
futures = [
executor.submit(query, q, nb)
for q, nb in zip(questions, notebooks)
]
results = [f.result() for f in futures]
Batch Processing
def batch_research(questions, notebook_id):
results = []
for question in questions:
result = subprocess.run([
"python", "scripts/run.py", "ask_question.py",
"--question", question,
"--notebook-id", notebook_id
], capture_output=True, text=True)
results.append(result.stdout)
time.sleep(2) # Avoid rate limits
return results
Module Classes
NotebookLibrary
add_notebook(url, name, topics)list_notebooks()search_notebooks(query)get_notebook(notebook_id)activate_notebook(notebook_id)remove_notebook(notebook_id)
AuthManager
is_authenticated()setup_auth(headless=False)get_auth_info()clear_auth()validate_auth()
BrowserSession (internal)
- Handles browser automation
- Manages stealth behavior
- Not intended for direct use
Best Practices
- Always use run.py - Ensures environment
- Check auth first - Before operations
- Handle rate limits - Implement retries
- Include context - Questions are independent
- Clean sessions - Use cleanup_manager
NotebookLM Skill Troubleshooting Guide
Quick Fix Table
| Error | Solution |
|---|---|
| ModuleNotFoundError | Use python scripts/run.py [script].py |
| Authentication failed | Browser must be visible for setup |
| Browser crash | python scripts/run.py cleanup_manager.py --preserve-library |
| Rate limit hit | Wait 1 hour or switch accounts |
| Notebook not found | python scripts/run.py notebook_manager.py list |
| Script not working | Always use run.py wrapper |
Critical: Always Use run.py
Most issues are solved by using the run.py wrapper:
# ✅ CORRECT - Always:
python scripts/run.py auth_manager.py status
python scripts/run.py ask_question.py --question "..."
# ❌ WRONG - Never:
python scripts/auth_manager.py status # ModuleNotFoundError!
Common Issues and Solutions
Authentication Issues
Not authenticated error
Error: Not authenticated. Please run auth setup first.
Solution:
# Check status
python scripts/run.py auth_manager.py status
# Setup authentication (browser MUST be visible!)
python scripts/run.py auth_manager.py setup
# User must manually log in to Google
# If setup fails, try re-authentication
python scripts/run.py auth_manager.py reauth
Authentication expires frequently
Solution:
# Clear old authentication
python scripts/run.py cleanup_manager.py --preserve-library
# Fresh authentication setup
python scripts/run.py auth_manager.py setup --timeout 15
# Use persistent browser profile
export PERSIST_AUTH=true
Google blocks automated login
Solution:
- Use dedicated Google account for automation
- Enable “Less secure app access” if available
- ALWAYS use visible browser:
python scripts/run.py auth_manager.py setup
# Browser MUST be visible - user logs in manually
# NO headless parameter exists - use --show-browser for debugging
Browser Issues
Browser crashes or hangs
TimeoutError: Waiting for selector failed
Solution:
# Kill hanging processes
pkill -f chromium
pkill -f chrome
# Clean browser state
python scripts/run.py cleanup_manager.py --confirm --preserve-library
# Re-authenticate
python scripts/run.py auth_manager.py reauth
Browser not found error
Solution:
# Install Chromium via run.py (automatic)
python scripts/run.py auth_manager.py status
# run.py will install Chromium automatically
# Or manual install if needed
cd ./
source .venv/bin/activate
python -m patchright install chromium
Rate Limiting
Rate limit exceeded (50 queries/day)
Solutions:
Option 1: Wait
# Check when limit resets (usually midnight PST)
date -d "tomorrow 00:00 PST"
Option 2: Switch accounts
# Clear current auth
python scripts/run.py auth_manager.py clear
# Login with different account
python scripts/run.py auth_manager.py setup
Option 3: Rotate accounts
# Use multiple accounts
accounts = ["account1", "account2"]
for account in accounts:
# Switch account on rate limit
subprocess.run(["python", "scripts/run.py", "auth_manager.py", "reauth"])
Notebook Access Issues
Notebook not found
Solution:
# List all notebooks
python scripts/run.py notebook_manager.py list
# Search for notebook
python scripts/run.py notebook_manager.py search --query "keyword"
# Add notebook if missing
python scripts/run.py notebook_manager.py add \
--url "https://notebooklm.google.com/..." \
--name "Name" \
--topics "topics"
Access denied to notebook
Solution:
- Check if notebook is still shared publicly
- Re-add notebook with updated URL
- Verify correct Google account is used
Wrong notebook being used
Solution:
# Check active notebook
python scripts/run.py notebook_manager.py list | grep "active"
# Activate correct notebook
python scripts/run.py notebook_manager.py activate --id correct-id
Virtual Environment Issues
ModuleNotFoundError
ModuleNotFoundError: No module named 'patchright'
Solution:
# ALWAYS use run.py - it handles venv automatically!
python scripts/run.py [any_script].py
# run.py will:
# 1. Create .venv if missing
# 2. Install dependencies
# 3. Run the script
Wrong Python version
Solution:
# Check Python version (needs 3.10+)
python --version
# If wrong version, specify correct Python
python3.10 scripts/run.py auth_manager.py status
Network Issues
Connection timeouts
Solution:
# Increase timeout
export TIMEOUT_SECONDS=60
# Check connectivity
ping notebooklm.google.com
# Use proxy if needed
export HTTP_PROXY=http://proxy:port
export HTTPS_PROXY=http://proxy:port
Data Issues
Corrupted notebook library
JSON decode error when listing notebooks
Solution:
# Backup current library
cp ./data/library.json library.backup.json
# Reset library
rm ./data/library.json
# Re-add notebooks
python scripts/run.py notebook_manager.py add --url ... --name ...
Disk space full
Solution:
# Check disk usage
df -h ./data/
# Clean up
python scripts/run.py cleanup_manager.py --confirm --preserve-library
Debugging Techniques
Enable verbose logging
export DEBUG=true
export LOG_LEVEL=DEBUG
python scripts/run.py ask_question.py --question "Test" --show-browser
Test individual components
# Test authentication
python scripts/run.py auth_manager.py status
# Test notebook access
python scripts/run.py notebook_manager.py list
# Test browser launch
python scripts/run.py ask_question.py --question "test" --show-browser
Save screenshots on error
Add to scripts for debugging:
try:
# Your code
except Exception as e:
page.screenshot(path=f"error_{timestamp}.png")
raise e
Recovery Procedures
Complete reset
#!/bin/bash
# Kill processes
pkill -f chromium
# Backup library if exists
if [ -f ./data/library.json ]; then
cp ./data/library.json ~/library.backup.json
fi
# Clean everything
cd ./
python scripts/run.py cleanup_manager.py --confirm --force
# Remove venv
rm -rf .venv
# Reinstall (run.py will handle this)
python scripts/run.py auth_manager.py setup
# Restore library if backup exists
if [ -f ~/library.backup.json ]; then
mkdir -p ./data/
cp ~/library.backup.json ./data/library.json
fi
Partial recovery (keep data)
# Keep auth and library, fix execution
cd ./
rm -rf .venv
# run.py will recreate venv automatically
python scripts/run.py auth_manager.py status
Error Messages Reference
Authentication Errors
| Error | Cause | Solution |
|---|---|---|
| Not authenticated | No valid auth | run.py auth_manager.py setup |
| Authentication expired | Session old | run.py auth_manager.py reauth |
| Invalid credentials | Wrong account | Check Google account |
| 2FA required | Security challenge | Complete in visible browser |
Browser Errors
| Error | Cause | Solution |
|---|---|---|
| Browser not found | Chromium missing | Use run.py (auto-installs) |
| Connection refused | Browser crashed | Kill processes, restart |
| Timeout waiting | Page slow | Increase timeout |
| Context closed | Browser terminated | Check logs for crashes |
Notebook Errors
| Error | Cause | Solution |
|---|---|---|
| Notebook not found | Invalid ID | run.py notebook_manager.py list |
| Access denied | Not shared | Re-share in NotebookLM |
| Invalid URL | Wrong format | Use full NotebookLM URL |
| No active notebook | None selected | run.py notebook_manager.py activate |
Prevention Tips
- Always use run.py - Prevents 90% of issues
- Regular maintenance - Clear browser state weekly
- Monitor queries - Track daily count to avoid limits
- Backup library - Export notebook list regularly
- Use dedicated account - Separate Google account for automation
Getting Help
Diagnostic information to collect
# System info
python --version
cd ./
ls -la
# Skill status
python scripts/run.py auth_manager.py status
python scripts/run.py notebook_manager.py list | head -5
# Check data directory
ls -la ./data/
Common questions
Q: Why doesn’t this work in Claude web UI? A: Web UI has no network access. Use local Claude Code.
Q: Can I use multiple Google accounts?
A: Yes, use run.py auth_manager.py reauth to switch.
Q: How to increase rate limit? A: Use multiple accounts or upgrade to Google Workspace.
Q: Is this safe for my Google account? A: Use dedicated account for automation. Only accesses NotebookLM.
NotebookLM Skill Usage Patterns
Advanced patterns for using the NotebookLM skill effectively.
Critical: Always Use run.py
Every command must use the run.py wrapper:
# ✅ CORRECT:
python scripts/run.py auth_manager.py status
python scripts/run.py ask_question.py --question "..."
# ❌ WRONG:
python scripts/auth_manager.py status # Will fail!
Pattern 1: Initial Setup
# 1. Check authentication (using run.py!)
python scripts/run.py auth_manager.py status
# 2. If not authenticated, setup (Browser MUST be visible!)
python scripts/run.py auth_manager.py setup
# Tell user: "Please log in to Google in the browser window"
# 3. Add first notebook - ASK USER FOR DETAILS FIRST!
# Ask: "What does this notebook contain?"
# Ask: "What topics should I tag it with?"
python scripts/run.py notebook_manager.py add \
--url "https://notebooklm.google.com/notebook/..." \
--name "User provided name" \
--description "User provided description" \ # NEVER GUESS!
--topics "user,provided,topics" # NEVER GUESS!
Critical Notes:
- Virtual environment created automatically by run.py
- Browser MUST be visible for authentication
- ALWAYS discover content via query OR ask user for notebook metadata
Pattern 2: Adding Notebooks (Smart Discovery!)
When user shares a NotebookLM URL:
OPTION A: Smart Discovery (Recommended)
# 1. Query the notebook to discover its content
python 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]"
# 2. Use discovered info to add it
python scripts/run.py notebook_manager.py add \
--url "[URL]" \
--name "[Based on content]" \
--description "[From discovery]" \
--topics "[Extracted topics]"
OPTION B: Ask User (Fallback)
# If discovery fails, ask user:
"What does this notebook contain?"
"What topics does it cover?"
# Then add with user-provided info:
python scripts/run.py notebook_manager.py add \
--url "[URL]" \
--name "[User's answer]" \
--description "[User's description]" \
--topics "[User's topics]"
NEVER:
- Guess what’s in a notebook
- Use generic descriptions
- Skip discovering content
Pattern 3: Daily Research Workflow
# Check library
python scripts/run.py notebook_manager.py list
# Research with comprehensive questions
python scripts/run.py ask_question.py \
--question "Detailed question with all context" \
--notebook-id notebook-id
# Follow-up when you see "Is that ALL you need to know?"
python scripts/run.py ask_question.py \
--question "Follow-up question with previous context"
Pattern 4: Follow-Up Questions (CRITICAL!)
When NotebookLM responds with “EXTREMELY IMPORTANT: Is that ALL you need to know?”:
# 1. STOP - Don't respond to user yet
# 2. ANALYZE - Is answer complete?
# 3. If gaps exist, ask follow-up:
python scripts/run.py ask_question.py \
--question "Specific follow-up with context from previous answer"
# 4. Repeat until complete
# 5. Only then synthesize and respond to user
Pattern 5: Multi-Notebook Research
# Query different notebooks for comparison
python scripts/run.py notebook_manager.py activate --id notebook-1
python scripts/run.py ask_question.py --question "Question"
python scripts/run.py notebook_manager.py activate --id notebook-2
python scripts/run.py ask_question.py --question "Same question"
# Compare and synthesize answers
Pattern 6: Error Recovery
# If authentication fails
python scripts/run.py auth_manager.py status
python scripts/run.py auth_manager.py reauth # Browser visible!
# If browser crashes
python scripts/run.py cleanup_manager.py --preserve-library
python scripts/run.py auth_manager.py setup # Browser visible!
# If rate limited
# Wait or switch accounts
python scripts/run.py auth_manager.py reauth # Login with different account
Pattern 7: Batch Processing
#!/bin/bash
NOTEBOOK_ID="notebook-id"
QUESTIONS=(
"First comprehensive question"
"Second comprehensive question"
"Third comprehensive question"
)
for question in "${QUESTIONS[@]}"; do
echo "Asking: $question"
python scripts/run.py ask_question.py \
--question "$question" \
--notebook-id "$NOTEBOOK_ID"
sleep 2 # Avoid rate limits
done
Pattern 8: Automated Research Script
#!/usr/bin/env python
import subprocess
def research_topic(topic, notebook_id):
# Comprehensive question
question = f"""
Explain {topic} in detail:
1. Core concepts
2. Implementation details
3. Best practices
4. Common pitfalls
5. Examples
"""
result = subprocess.run([
"python", "scripts/run.py", "ask_question.py",
"--question", question,
"--notebook-id", notebook_id
], capture_output=True, text=True)
return result.stdout
Pattern 9: Notebook Organization
# Organize by domain - with proper metadata
# ALWAYS ask user for descriptions!
# Backend notebooks
add_notebook("Backend API", "Complete API documentation", "api,rest,backend")
add_notebook("Database", "Schema and queries", "database,sql,backend")
# Frontend notebooks
add_notebook("React Docs", "React framework documentation", "react,frontend")
add_notebook("CSS Framework", "Styling documentation", "css,styling,frontend")
# Search by domain
python scripts/run.py notebook_manager.py search --query "backend"
python scripts/run.py notebook_manager.py search --query "frontend"
Pattern 10: Integration with Development
# Query documentation during development
def check_api_usage(api_endpoint):
result = subprocess.run([
"python", "scripts/run.py", "ask_question.py",
"--question", f"Parameters and response format for {api_endpoint}",
"--notebook-id", "api-docs"
], capture_output=True, text=True)
# If follow-up needed
if "Is that ALL you need" in result.stdout:
# Ask for examples
follow_up = subprocess.run([
"python", "scripts/run.py", "ask_question.py",
"--question", f"Show code examples for {api_endpoint}",
"--notebook-id", "api-docs"
], capture_output=True, text=True)
return combine_answers(result.stdout, follow_up.stdout)
Best Practices
1. Question Formulation
- Be specific and comprehensive
- Include all context in each question
- Request structured responses
- Ask for examples when needed
2. Notebook Management
- ALWAYS ask user for metadata
- Use descriptive names
- Add comprehensive topics
- Keep URLs current
3. Performance
- Batch related questions
- Use parallel processing for different notebooks
- Monitor rate limits (50/day)
- Switch accounts if needed
4. Error Handling
- Always use run.py to prevent venv issues
- Check auth before operations
- Implement retry logic
- Have fallback notebooks ready
5. Security
- Use dedicated Google account
- Never commit data/ directory
- Regularly refresh auth
- Track all access
Common Workflows for Claude
Workflow 1: User Sends NotebookLM URL
# 1. Detect URL in message
if "notebooklm.google.com" in user_message:
url = extract_url(user_message)
# 2. Check if in library
notebooks = run("notebook_manager.py list")
if url not in notebooks:
# 3. ASK USER FOR METADATA (CRITICAL!)
name = ask_user("What should I call this notebook?")
description = ask_user("What does this notebook contain?")
topics = ask_user("What topics does it cover?")
# 4. Add with user-provided info
run(f"notebook_manager.py add --url {url} --name '{name}' --description '{description}' --topics '{topics}'")
# 5. Use the notebook
answer = run(f"ask_question.py --question '{user_question}'")
Workflow 2: Research Task
# 1. Understand task
task = "Implement feature X"
# 2. Formulate comprehensive questions
questions = [
"Complete implementation guide for X",
"Error handling for X",
"Performance considerations for X"
]
# 3. Query with follow-ups
for q in questions:
answer = run(f"ask_question.py --question '{q}'")
# Check if follow-up needed
if "Is that ALL you need" in answer:
# Ask more specific question
follow_up = run(f"ask_question.py --question 'Specific detail about {q}'")
# 4. Synthesize and implement
Tips and Tricks
- Always use run.py - Prevents all venv issues
- Ask for metadata - Never guess notebook contents
- Use verbose questions - Include all context
- Follow up automatically - When you see the prompt
- Monitor rate limits - 50 queries per day
- Batch operations - Group related queries
- Export important answers - Save locally
- Version control notebooks - Track changes
- Test auth regularly - Before important tasks
- Document everything - Keep notes on notebooks
Quick Reference
# Always use run.py!
python scripts/run.py [script].py [args]
# Common operations
run.py auth_manager.py status # Check auth
run.py auth_manager.py setup # Login (browser visible!)
run.py notebook_manager.py list # List notebooks
run.py notebook_manager.py add ... # Add (ask user for metadata!)
run.py ask_question.py --question ... # Query
run.py cleanup_manager.py ... # Clean up
Remember: When in doubt, use run.py and ask the user for notebook details!