nlm — NotebookLM CLI

SkillFiles & storage

Lets your agent create and manage Google NotebookLM notebooks, add sources, chat with them, and generate reports.

Use nlm — NotebookLM CLI in Claude, ChatGPT or Ahel Desktop

Free. Sign in, add nlm — NotebookLM CLI and connect your AI. About a minute.

Also: Claude Code · Cursor · Codex

Then ask your AI: use the nlm skill

Details

Instructions available. Your AI can read the instructions. Execution depends on the setup they require.

Add Ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

nlm — NotebookLM CLIStart free
About this skill

Manages Google NotebookLM notebooks via the nlm CLI. Use for creating notebooks, listing and syncing sources, uploading files/URLs/text, chatting with sources, generating reports/audio/video/slides, running research, managing labels, editing notebook metadata (title/emoji/description/cover), and man

What this skill tells your AI

The instructions your AI receives, as published by tmc/nlm in skills/nlm/SKILL.md and read by Ahel’s review.

Command Discovery

Run nlm --help for the canonical command tree. Run nlm <command> --help for command-local flags. The stable surface is noun-first: notebook, source, note, artifact, and chat groups.

For a compact command map, read reference/commands.md only when needed. Always prefer live help output when it disagrees with the reference.

Interpreting $ARGUMENTS

ArgumentAction
(empty)Run nlm notebook list, then ask what to do
create or newCreate a notebook with nlm notebook create
upload or addAdd one-off sources with nlm source add
syncSync a directory as a managed source with nlm source sync
chatStart, resume, or run one-shot chat
researchRun nlm research and choose fast/deep mode if needed
audio / video / slides / reportUse the corresponding create or generation command
statusShow notebook, sources, artifacts, and recent chats
a notebook IDShow details for that notebook
a file path or globUpload that file/pattern to a notebook

Critical Practices

  • Surface full UUIDs for notebooks, sources, conversations, notes, and artifacts in responses. Follow-up commands need them.
  • Use -y for destructive operations in non-interactive contexts, for example nlm -y notebook delete <id>.
  • Use nlm auth --authuser N or NLM_AUTHUSER=N for non-default Google accounts.
  • Use --direct-rpc for audio download; if the direct fetch is unavailable, it prints the NotebookLM browser URL. video download enables the required direct-RPC path itself and uses the same browser fallback.
  • Prefer canonical grouped commands in all new guidance.

Common Workflows

List notebooks

nlm notebook list
nlm notebook list --limit 25
nlm notebook list --all

Add one-off sources — use source add for files, URLs, and direct text. Pass - to read newline-delimited source references from stdin.

nlm source add <notebook-id> https://example.com/article
nlm source add <notebook-id> ./paper.pdf
nlm source add --name "API notes" <notebook-id> ./notes.txt
printf '%s\n' ./a.pdf https://example.com/b | nlm source add <notebook-id> -

Sync a directory as one source — source sync packs files into txtar, quotes nested txtar markers, chunks large payloads, and skips unchanged chunks using a content-hash cache. Use it whenever the same tree will be re-uploaded. Use source add for one-shot single-file/URL uploads.

nlm source sync <notebook-id> src/
nlm source sync --name "project: src/" <notebook-id> src/
nlm source sync --dry-run <notebook-id> .
nlm source sync --force <notebook-id> ./docs ./notes
nlm source sync --json <notebook-id> .

Preview what sync will upload — source pack writes the exact txtar bytes sync would upload, no network. Pipe through txtar --list or txtar -x to inspect:

nlm source pack src/ | txtar --list
nlm source pack src/ > preview.txtar
nlm source pack --chunk 2 src/ > pt2.txtar

Focus on specific sources — --source-ids and --source-match scope chat, generate-chat, generate-report, source-guide, and content transforms. --source-match is a Go regex matched against titles and UUIDs.

nlm chat --source-match 'internal/sync' <notebook-id> "What changed?"
nlm generate-chat --source-ids a,b,c <notebook-id> "Summarize these"
nlm summarize --source-match '^spec/' <notebook-id>
nlm source list <notebook-id> | grep Q3 | nlm chat --source-ids - <notebook-id> "Risks?"

Chat and continuation

nlm chat <notebook-id>
nlm chat <notebook-id> "What are the main conclusions?"
nlm generate-chat --conversation <conversation-id> <notebook-id> "Follow up"
nlm chat show --citations tail <notebook-id> <conversation-id>

Research

nlm research <notebook-id> "What changed in the source set?"
nlm research --mode fast <notebook-id> "Which docs should I read first?"
nlm research --md <notebook-id> "Write a concise brief" > report.md
nlm research --import <notebook-id> "Find source material"

Content creation — creation may take time. Poll with artifact list, audio list, or video list.

nlm create-audio <notebook-id> "Conversational, focus on key decisions"
nlm create-video <notebook-id> "Whiteboard walkthrough"
nlm create-slides <notebook-id> "Presentation summary"
nlm generate-report --sections 3 <notebook-id>
nlm artifact list <notebook-id>
nlm --direct-rpc audio download <notebook-id> output.wav
nlm --direct-rpc video download <notebook-id> output.mp4

Rename after stdin upload — stdin text defaults to "Pasted Text"; use --name during upload or rename after:

nlm source rename <source-id> "descriptive name"

Notebook metadata — title, emoji, description, and cover are separate commands. cover takes a built-in preset ID; cover-image uploads a custom image. unrecent only hides from the recents list, it does not delete.

nlm notebook rename <notebook-id> "New Title"
nlm notebook emoji <notebook-id> "📓"
nlm notebook description <notebook-id> "One-line summary"
echo "long description" | nlm notebook description <notebook-id>
nlm notebook cover <notebook-id> 4
nlm notebook cover-image <notebook-id> ./cover.png
nlm notebook unrecent <notebook-id>

Labels (autolabel clusters) — labels are server-side clusters over sources. generate and relabel-all are heavy server jobs (relabel-all can exceed the 60s deadline on large notebooks); unlabeled only touches sources without a label. attach takes one source per call.

nlm label list <notebook-id>
nlm label generate <notebook-id>
nlm label create <notebook-id> "Important" "⭐"
nlm label rename <notebook-id> <label-id> "New Name"
nlm label emoji <notebook-id> <label-id> "🐛"
nlm label delete <notebook-id> <label-id> [<label-id>...]
nlm label unlabeled <notebook-id>
nlm label relabel-all <notebook-id>
nlm label attach <notebook-id> <label-id|name> <source-id|name>

Discover sources vs chat — discover-sources calls a server-driven source-discovery RPC (Es3dTe) that returns ranked source IDs for a query. If the server rejects it (error or transient code-13), the CLI falls back to a regular chat call asking the model to list relevant sources. Use it to pick --source-ids for a follow-up; use nlm chat when you want a narrative answer rather than just IDs.

nlm discover-sources <notebook-id> "Q3 revenue assumptions"

Source Freshness Strategy

Pick the lightest tool that does the job:

  • nlm source check <source-id> [notebook-id] — Drive-only. Asks Google whether the indexed copy is still current. No re-index, no upload. Use to decide whether anything else is needed.
  • nlm source refresh <notebook-id> <source-id> — Drive-only. Re-indexes the existing source in place. Use when check reports stale and the source is still a Google Drive document.
  • Re-upload — for non-Drive sources (files, URLs, pasted text) check and refresh do not apply. Use nlm source delete then nlm source add, or for a synced tree run nlm source sync (it auto-detects changed chunks; --force to re-upload unchanged content).

Binary upload workarounds — if a binary upload fails, convert to text:

pdftotext paper.pdf - | nlm source add --name "paper text" <notebook-id> -
plutil -convert xml1 -o - file.plist | nlm source add --name "plist text" <notebook-id> -

Error Recovery

ErrorFix
"Authentication required"Run nlm auth
"Service unavailable" on uploadRetry after a few seconds (rate limit)
"source limit reached" or "Failed precondition" on addRemove unused sources or use a smaller target notebook
"upload init failed (status 500)"Try text extraction workaround
--source-match matched no sourcesRe-run nlm source list <notebook-id> and adjust the regex

Signals

GitHub stars
391
Forks
53
Last commit
Sep 2026
Advanced
Item type
skill
Key
nlm-tmc
Source
github.com/tmc/nlm