Open Notebook does what Google's NotebookLM does, on a server you control. You collect sources into notebooks (PDFs, web pages, videos, audio files and plain text), it extracts and indexes them with full-text and vector search, and you chat with a model that answers from those sources. Transformations run one prompt across every source, such as a summary or key-points pass, and the podcast generator writes and voices a discussion of your material with one to four speakers whose profiles you define, where NotebookLM fixes it at two.
The other difference is model choice. Through the author's Esperanto library it supports 18 or more providers, including OpenAI, Anthropic, Google, Mistral, Groq, ElevenLabs and OpenRouter, plus local models through Ollama or LM Studio, and you pick a model separately for chat, embeddings, speech-to-text and text-to-speech. It also has a full REST API, which NotebookLM lacks. The README is candid that its citations are basic compared with Google's.
It is built by Luis Novo, MIT-licensed, with about 39,700 stars, and runs as two Docker containers: the app, with a Next.js front end and a Python API, and a SurrealDB database. KDnuggets and others have covered it as a private, open-source NotebookLM alternative.
- Repository: github.com/lfnovo/open-notebook
- Licence: MIT (MIT License)
- Language: TypeScript. Stars: 39.7K. Forks: 4,595. Last push: Oct 3, 2026.
- Scan: safe, Oct 3, 2026, commit 5f021c5
Who it is for
Researchers, students and analysts who like NotebookLM but cannot upload their material to Google, or who want to choose and pay for their own models, including fully local ones.
Getting started
1. Download the Compose file (Docker Desktop required)
curl -o docker-compose.yml https://raw.githubusercontent.com/lfnovo/open-notebook/main/docker-compose.yml2. Set OPEN_NOTEBOOK_ENCRYPTION_KEY in docker-compose.yml to your own secret, then start it
docker compose up -d3. Open the UI after 15 to 20 seconds, then add a provider and API key under Models
open http://localhost:8502The encryption key protects the API keys stored in the database, so change it before the first start. SurrealDB defaults to root:root and is bound to localhost; set SURREAL_USER and SURREAL_PASSWORD in a .env file before exposing the instance to a network. The repository's examples folder has an Ollama Compose file for a setup with no API costs.
Safety scan
We cloned lfnovo/open-notebook at commit 5f021c5 on Oct 3, 2026 and ran the checks described on the GitHub Tools page: credential patterns, decode-and-execute code, install-time scripts, committed binaries, risky CI workflows, every host the code talks to, known vulnerabilities in pinned dependencies, and project hygiene. A person read every hit. This is what we found.
- No secrets across 634 files and about 109,000 lines of TypeScript and Python. The single pattern hit is Dockerfile line 77, which installs Node.js 22 into the image with NodeSource's setup script piped to bash; it runs when the image is built, not on your machine.
- The six bare-IP URLs are tests for the URL validator that guards custom model endpoints: 93.184.216.34, the long-time address of example.com, stands in for a public host, and 100.101.102.103 for a Tailscale-style private address.
- Six known advisories (3 high, 3 moderate) across 1,094 packages, few for a project this size. frontend/package-lock.json has braces and Vitest issues in build and test tooling; uv.lock has click and lxml-html-clean, the second relevant to cleaning HTML from web pages you add as sources.
- The defaults are the thing to change. docker-compose.yml starts SurrealDB with root:root, bound to 127.0.0.1 so it is not exposed by default, and OPEN_NOTEBOOK_ENCRYPTION_KEY is set to change-me-to-a-secret-string; that key protects the provider API keys stored in the database. The app itself on port 8502 has no login.
- Four workflows, none using pull_request_target, and all 20 third-party actions pinned to commits. Security policy, Dependabot, licence, contributing guide and code of conduct present; no CodeQL.
What the scanner counted
| Check | Result |
|---|---|
| Secrets | None found. |
| Suspicious code | 1 pattern hit found and read; every one is listed under the raw findings. |
| Install-time code | None: nothing runs at install beyond the package manager itself. |
| Committed binaries | None. |
| CI workflows | 4 workflows. None use pull_request_target. 0 of 20 third-party actions pinned to a tag rather than a commit. |
| Network hosts | 40 distinct hosts referenced from source; most often api.example.com, host.docker.internal, github.com, notebook.example.com. 6 URLs to a bare IP address, listed under the raw findings. |
| Known vulnerabilities | 6 advisories across 1,094 pinned packages: 0 critical, 3 high, 3 moderate, 0 low. frontend/package-lock.json: 878 packages, 4 advisories; uv.lock: 236 packages, 2 advisories. |
| Project hygiene | Has security policy, automated dependency updates, licence file, contributing guide. Missing CodeQL. |
| OpenSSF Scorecard | Not scored: the project is not in Scorecard's weekly index. |
The raw findings
Every hit the scanner wrote out, with a link to the exact line at the scanned commit. Secrets candidates are redacted.
Pattern hits (1)
| Where | Rule | Match |
|---|---|---|
| Dockerfile:77 | download-piped-to-shell | && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ |
URLs to bare IP addresses (6)
| Where | Rule | Match |
|---|---|---|
| tests/test_credentials_api.py:296 | ip-literal-url | url="https://93.184.216.34/v1/models", |
| tests/test_credentials_api.py:318 | ip-literal-url | assert captured["url"] == "https://93.184.216.34/v1/models" |
| tests/test_url_validation.py:214 | ip-literal-url | assert target.url == "https://93.184.216.34/v1/models" |
| tests/test_url_validation.py:231 | ip-literal-url | assert target.url == "https://93.184.216.34/v1/models" |
| tests/test_url_validation.py:340 | ip-literal-url | assert target.url == "http://100.101.102.103:11434/api/tags" |
| tests/test_url_validation.py:373 | ip-literal-url | assert target.url == "https://93.184.216.34/v1/models?type=all" |
Worst known vulnerabilities (6 of 6)
| Advisory | Severity | Package | Summary |
|---|---|---|---|
| GHSA-vfj7-8cjw-p6xm | high | braces@3.0.3 | braces vulnerable to stack-exhaustion denial of service through deeply nested patterns |
| GHSA-47fr-3ffg-hgmw | high | click@8.3.1 | |
| GHSA-4jhm-jv67-739f | high | lxml-html-clean@0.4.4 | `lxml_html_clean.Cleaner` does not strip `javascript:` URLs from namespaced URL attributes |
| GHSA-82fw-gwwq-j7x9 | moderate | @vitest/mocker@4.1.9 | Vitest: Path Traversal / Arbitrary File Read via @vitest/mocker Redirect Mock |
| GHSA-px8p-9vwx-vf98 | moderate | fflate@0.8.2 | fflate unzipSync can enter an infinite loop when parsing malformed ZIP64 archives |
| GHSA-82fw-gwwq-j7x9 | moderate | vitest@4.1.9 | Vitest: Path Traversal / Arbitrary File Read via @vitest/mocker Redirect Mock |
By the numbers
| Stars | 39.7K |
|---|---|
| Forks | 4,595 |
| Contributors | 87 |
| Commits | 998 |
| Open issues | 108 |
| Open pull requests | 19 |
| Releases | 42 |
| Latest release | v1.14.0 |
| Licence | MIT |
| Main language | TypeScript |
| Project age | 1 year |
| Last push | Oct 3, 2026 |
| Tracked files | 634 |
| Lines of code | 108.8K |
| Checkout size | 6 MB |
Lines by language: TypeScript 44.3K, Python 35.4K, Markdown 24.8K, YAML 2,029, TOML 1,084, Shell 516.
Questions
Is Open Notebook free?
Yes. Open Notebook is MIT-licensed with no paid tier. You pay only for the AI providers you connect, per token at their prices, or nothing if you run models locally with Ollama or LM Studio. Groq and Google AI Studio have free API tiers that are enough to try it.
How is Open Notebook different from NotebookLM?
It is self-hosted, works with many model providers instead of only Google's, supports one to four podcast speakers instead of two, lets you write custom transformations, and has a REST API. NotebookLM has stronger citations and needs no setup. Both take PDFs, web pages, video and audio.
Can Open Notebook run fully locally?
Yes, with some setup. Ollama covers chat and embeddings, so sources and notes never leave your machine. Podcasts also need speech-to-text and text-to-speech, which Ollama does not provide; a local OpenAI-compatible speech server can fill that role, or you can use a cloud provider such as OpenAI, Google or ElevenLabs for that step only.
This post is part of GitHub Tools, where every repository is cloned and scanned before it is written up. The scan is a snapshot of one commit on one day; the repository has moved on since, so check it before you install.
