5 min read

Open Notebook: A Self-Hosted NotebookLM (GitHub, Scanned)

A self-hosted NotebookLM: chat with your PDFs, videos and web pages, and turn them into podcasts.

Open Notebook logo
✅
Scan: safe. Nothing malicious. One thing to know: the stock Compose file runs SurrealDB as root:root and ships a placeholder encryption key, so change both before the instance is reachable from anywhere but your own machine. Scanned Oct 3, 2026; the full report is below.

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.

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.yml

2. Set OPEN_NOTEBOOK_ENCRYPTION_KEY in docker-compose.yml to your own secret, then start it

docker compose up -d

3. Open the UI after 15 to 20 seconds, then add a provider and API key under Models

open http://localhost:8502

The 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

CheckResult
SecretsNone found.
Suspicious code1 pattern hit found and read; every one is listed under the raw findings.
Install-time codeNone: nothing runs at install beyond the package manager itself.
Committed binariesNone.
CI workflows4 workflows. None use pull_request_target. 0 of 20 third-party actions pinned to a tag rather than a commit.
Network hosts40 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 vulnerabilities6 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 hygieneHas security policy, automated dependency updates, licence file, contributing guide. Missing CodeQL.
OpenSSF ScorecardNot 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)
WhereRuleMatch
Dockerfile:77download-piped-to-shell&& curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
URLs to bare IP addresses (6)
WhereRuleMatch
tests/test_credentials_api.py:296ip-literal-urlurl="https://93.184.216.34/v1/models",
tests/test_credentials_api.py:318ip-literal-urlassert captured["url"] == "https://93.184.216.34/v1/models"
tests/test_url_validation.py:214ip-literal-urlassert target.url == "https://93.184.216.34/v1/models"
tests/test_url_validation.py:231ip-literal-urlassert target.url == "https://93.184.216.34/v1/models"
tests/test_url_validation.py:340ip-literal-urlassert target.url == "http://100.101.102.103:11434/api/tags"
tests/test_url_validation.py:373ip-literal-urlassert target.url == "https://93.184.216.34/v1/models?type=all"
Worst known vulnerabilities (6 of 6)
AdvisorySeverityPackageSummary
GHSA-vfj7-8cjw-p6xmhighbraces@3.0.3braces vulnerable to stack-exhaustion denial of service through deeply nested patterns
GHSA-47fr-3ffg-hgmwhighclick@8.3.1
GHSA-4jhm-jv67-739fhighlxml-html-clean@0.4.4`lxml_html_clean.Cleaner` does not strip `javascript:` URLs from namespaced URL attributes
GHSA-82fw-gwwq-j7x9moderate@vitest/mocker@4.1.9Vitest: Path Traversal / Arbitrary File Read via @vitest/mocker Redirect Mock
GHSA-px8p-9vwx-vf98moderatefflate@0.8.2fflate unzipSync can enter an infinite loop when parsing malformed ZIP64 archives
GHSA-82fw-gwwq-j7x9moderatevitest@4.1.9Vitest: Path Traversal / Arbitrary File Read via @vitest/mocker Redirect Mock

By the numbers

Stars39.7K
Forks4,595
Contributors87
Commits998
Open issues108
Open pull requests19
Releases42
Latest releasev1.14.0
LicenceMIT
Main languageTypeScript
Project age1 year
Last pushOct 3, 2026
Tracked files634
Lines of code108.8K
Checkout size6 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.