notebooklm-py

repository·main·Indexed 12 days ago

https://github.com/teng-lin/notebooklm-py

An unofficial Python library, API, and CLI for automating Google Gemini Notebook (formerly NotebookLM). Version 0.8.0 provides programmatic access to research, synthesis, and content generation capabilities, specifically optimized for AI agent workflows like Claude Code and automated research pipelines. Includes a notebooklm-mcp server for integration with Claude and ChatGPT via OAuth or Bearer tokens.

Tokens
228.8K
Snippets
555
Records
895
Agent score
90%

What's inside notebooklm-py

  1. Overview of notebooklm-py

    main

    notebooklm-py

    notebooklm-py is a comprehensive, unofficial Python API and CLI for Google Gemini Notebook (formerly NotebookLM). It provides programmatic access to NotebookLM's features, including capabilities not available in the web UI.

    Key Capabilities:

    • AI Agent Tools: Integration with agents like Claude Code, Codex, and OpenClaw via MCP servers and custom skills.
    • Research Automation: Bulk-importing sources (URLs, PDFs, YouTube, Google Drive) and running research queries.
    • Content Generation: Programmatic generation of Audio Overviews (podcasts), videos, slide decks, quizzes, flashcards, infographics, data tables, mind maps, and study guides.
    • Downloads & Export: Batch downloading generated artifacts (MP3, MP4, PDF, PNG, CSV, JSON, Markdown) and exporting to Google Docs/Sheets.

    ⚠️ Warning: This is an unofficial library using undocumented Google APIs. It is not affiliated with Google. APIs may change without notice, and rate limits apply. Best suited for prototypes, research, and personal projects.

  2. Understand the NotebookLM Android API transport and service surface

    main

    The NotebookLM Android API uses gRPC over HTTP/2 to communicate with the backend. Unlike the web client which uses batchexecute (JSON), the mobile client uses protobuf messages with length-prefixed framing.

    Connection Details

    • Host: notebooklm-pa.googleapis.com:443
    • Service: google.internal.labs.tailwind.orchestration.v1.LabsTailwindOrchestrationService
    • Transport: HTTP/2 POST with content-type: application/grpc
    • Auth: OAuth bearer header
    • Success Indicator: HTTP 200 with trailer grpc-status: 0

    Service Surface

    The full API surface consists of 49 methods across 4 gRPC services extracted from the app binary:

    1. LabsTailwindOrchestrationService (44 methods): Core notebook, source, artifact, and chat functionality.
    2. LabsTailwindSharingService (3 methods): Project sharing and access requests.
    3. LabsTailwindDiscoveryService (1 method): Notebook search.
    4. LiveSessionService (1 method): WebRTC interactive-audio "Live" sessions.
  3. Historical context of Session and Runtime Adapters

    main

    This ADR (Architectural Decision Record) describes a historical architectural shift in notebooklm-py. Previously, the library used a Session facade class that acted as a 'god-object', satisfying all feature-specific Protocols (like ChatRuntime, ArtifactsRuntime, and UploadRuntime).

    Note for Developers: The Session class and _session.py module have been deleted. The functionality previously handled by Session and its collaborators has been moved to the _runtime/ package (e.g., _runtime/init.py, _runtime/transport.py). The classes SessionTransport and SessionCollaborators have been renamed to RuntimeTransport and RuntimeCollaborators respectively.

    For the current, live runtime shape, refer to docs/architecture.md instead of this ADR.

  4. Overview of notebooklm-py API Routes

    main

    The notebooklm-py application exposes several resource-specific FastAPI routers that map to core client functionalities. These routes allow for managing notebooks, sources, notes, chat, artifacts, research, and sharing. Most handlers interact with the _app core layer and use _app.serialize.to_jsonable for responses.

    Available resource routes:
    - `/v1/notebooks`: list, get, create, rename (PATCH), delete, and suggested prompts
    - `/v1/notebooks/{id}/sources`: list, get, add (url, text, file, drive, batch), rename (PATCH), wait, delete, and status polling
    - `/v1/notebooks/{id}/notes`: list, get, create, update (PUT), delete
    - `/v1/notebooks/{id}/chat`: blocking ask and configuration
    - `/v1/notebooks/{id}/artifacts`: list, generate, poll, download, rename (PATCH), retry, delete, and prompt retrieval
    - `/v1/notebooks/{id}/research`: start, status, cancel, and import
    - `/v1/notebooks/{id}/share`: status, public, and user view-level management
    - `/v1/server/info`: server version and auth-health probe
  5. What is DBSC and how does it affect authentication?

    main

    Device-Bound Session Credentials (DBSC) is a security mechanism designed to prevent cookie theft by binding a session to a private key stored in a device's hardware (TPM/Secure Enclave).

    Impact on Users:

    • Current State: DBSC is currently being rolled out and primarily targets the Chrome browser.
    • Compatibility: Non-Chrome HTTP clients (like httpx, curl, or Firefox) can still use the legacy unsigned RotateCookies endpoint. This means current HTTP-only strategies in notebooklm-py remain functional.
    • Future Risk: If Google extends DBSC enforcement to the unsigned endpoint, HTTP-only clients will break. The mitigation path involves using the L3 CDP attach arm to parasitize a real DBSC-enrolled Chrome session or using an operator-provided NOTEBOOKLM_REFRESH_CMD.
  6. How SemaphoreMiddleware and RetryMiddleware interact

    main

    The placement of SemaphoreMiddleware relative to RetryMiddleware is critical to prevent deadlocks and ensure correct resource management:

    1. Deadlock Prevention: SemaphoreMiddleware is placed outside (before) RetryMiddleware. This ensures that a single logical RPC (including all its retry attempts) only occupies one semaphore slot. If it were inside, every retry attempt would try to acquire a new slot, leading to deadlocks during sustained 429 (Too Many Requests) errors.
    2. Metrics Accuracy: MetricsMiddleware is placed before SemaphoreMiddleware so that the recorded rpc_latency_seconds_total includes the time spent waiting in the semaphore queue.
    3. Drain Invariant: DrainMiddleware is at the start of the chain (position 0) to ensure that even requests waiting for a semaphore slot are counted as 'in-flight', allowing client.close() to wait for them correctly.
  7. Handling asynchronous generation commands

    main

    Most generation commands are asynchronous by default and return a task ID immediately.

    • Synchronous: mind-map is the only command that completes instantly (it does not support --wait).
    • Asynchronous: All other generate commands return immediately (defaulting to --no-wait).
    • Waiting: Use the --wait flag to block until completion, or use artifact wait <id> in a background task.
    • Cancellation: Long-running tasks (--wait, artifact wait, source wait) honor SIGINT (Ctrl-C). When cancelled, the CLI exits with code 130 and provides a resume hint. In --json mode, cancellation returns {"error": true, "code": "CANCELLED", "resume_hint": "..."}.
  8. Difference between parse-time and post-parse errors

    main

    The CLI distinguishes between errors that happen during argument parsing and errors that happen during command execution:

    FeatureParse-time Errors (Argv-level)Post-parse Errors (Command/Service-level)
    TriggerInvalid flags, missing arguments, or type mismatches in argv.Semantic validation, precondition conflicts, or service failures.
    JSON BehaviorWrapped in JSON envelope under --json (via SectionedGroup.main).Wrapped in JSON envelope under --json (via handle_errors).
    Exit CodeTypically 2 (for UsageError/BadParameter) or 1.Typically 1 (for VALIDATION_ERROR).
    Text ModeRenders Click's standard Usage: ... / Error: ... text.Renders a human-readable message (omitting the usage footer).
  9. How to specify notebooks for CLI commands

    main

    There are three ways to specify which notebook a command should act upon. The resolution precedence is: -n/--notebook flag > NOTEBOOKLM_NOTEBOOK env var > active context > error.

    1. Flag: Use -n <id> or --notebook <id> directly on each command.
    2. Environment Variable: Set NOTEBOOKLM_NOTEBOOK=<id> in your shell.
    3. Active Context: Use notebooklm use <id> to set a persistent context for the current profile.
  10. Understand the NotebookLMClient concurrency model

    main

    The NotebookLMClient is async re-entrant on a single event loop. This means you can use asyncio.gather or asyncio.TaskGroup to run multiple operations concurrently.

    Important Constraints:

    • Not thread-safe: Do not share a single NotebookLMClient instance across different threads or multiple event loops. You must create one client per loop.
    • Loop-affinity: If you attempt to share a client across loops, the client will raise a RuntimeError on the authed POST path.
    notebooks, sources = await asyncio.gather(
        client.notebooks.list(),
        client.sources.list(notebook_id),
    )
  11. Use RpcRequest.context for metadata

    main

    The RpcRequest.context is a dict[str, Any] used as a permanent metadata carrier across the middleware chain. It is the primary way middlewares communicate state (like retry budgets or auth status) to one another.

    Important Rules for Developers:

    • Vocabulary is Bounded: You should not invent new keys. Any new key used by a middleware or the terminal requires an ADR update to the project's vocabulary table.
    • Reuse Existing Keys: If you need to signal a behavior (e.g., skipping retries), check if an existing key like disable_internal_retries can be used.
    • Avoid Local Ephemera: If state is only needed within a single await next_call(request) boundary and is not observed by other middlewares, do not use context. Use a contextvars.ContextVar or instance state instead.

    Commonly used context keys:

    • rpc_method: The name of the RPC method.
    • disable_internal_retries: Boolean to skip retry/refresh logic (used for non-idempotent writes).
    • auth_snapshot: The current authentication state.
    • auth_refreshed: Boolean indicating if a refresh has already occurred in this call.
    • retry_deadline: The aggregate deadline for the logical call to prevent infinite retries.
  12. Understand the Architecture Decision Record (ADR) process

    main

    The notebooklm-py project uses Architecture Decision Records (ADRs) to document the reasoning behind significant architectural choices. This prevents the re-litigation of established trade-offs.

    When an ADR is required

    An ADR must be created or updated when a Pull Request changes the architectural shape of the codebase. This includes:

    • Adding, removing, or relocating modules in:
      • src/notebooklm/_runtime/
      • src/notebooklm/_middleware/
      • src/notebooklm/auth.py
      • src/notebooklm/_auth/
      • src/notebooklm/cli/services/
    • Changing contracts between layers (e.g., CLI ↔ Client ↔ Core ↔ RPC).
    • Introducing new or retiring test patterns (fixtures, monkeypatch policy, conformance tests).
    • Implementing new cross-cutting policies (retry, idempotency, scrubbing, loop affinity).

    Note: Pure bug fixes, additive RPC method IDs, and CLI ergonomics changes do not require an ADR.