How to Contribute to Open Notebook Development: A Complete Guide

Open Notebook is a privacy-first, multi-provider AI research assistant built on a three-tier architecture (Next.js frontend, FastAPI backend, SurrealDB database) that requires an issue-first workflow, async Python code, and thorough testing for all contributions.

Open Notebook is an open-source research platform that orchestrates multi-provider LLMs through a clean, async-first architecture. Before contributing to the lfnovo/open-notebook repository, you must understand its strict domain-driven patterns and three-tier design. The following guide covers the essential architecture, design principles, and submission workflow required to get your pull request merged.

Architecture Overview

The codebase is organized into three distinct tiers that communicate via REST APIs, as documented in docs/7-DEVELOPMENT/architecture.md.

Frontend (Next.js, Port 8502)

The React-based UI renders notebooks, sources, notes, chat interfaces, and podcasts. It uses Zustand for global UI state management and TanStack Query for server-state caching. All data fetches target the REST API at http://localhost:5055.

API (FastAPI, Port 5055)

The async Python backend exposes CRUD endpoints for notebooks, sources, notes, chat sessions, search, and transformations. Router files in api/routers/*.py follow a service pattern, delegating business logic to service classes that invoke LangGraph workflows and the repository layer.

Database (SurrealDB, Port 8000)

A graph and vector database storing domain records (notebook, source, source_embedding, note, chat_session) with native embedding storage for semantic search. The database runs on port 8000 and manages relationships between research entities.

Core Design Principles

Every contribution must respect these five architectural constraints defined in docs/7-DEVELOPMENT/architecture.md.

Async-First Execution – All I/O operations must use await to maintain high concurrency. When modifying files in api/routers/ or service classes, ensure all database calls and external API requests remain asynchronous.

Domain-Driven Design – Business logic lives in open_notebook/domain/ (e.g., Notebook, Source, Note classes). Keep domain models separate from FastAPI networking code and UI components.

LangGraph Workflows – Multi-step AI tasks are implemented as state machines in open_notebook/graphs/*.py. New features requiring AI orchestration should add new graph definitions following existing patterns for source processing, chat, and transformations.

Multi-Provider AI via Esperanto – Never import provider-specific SDKs directly. Instead, use provision_langchain_model from open_notebook/ai/models.py to support 8+ LLM and embedding providers through a unified interface.

Job Queue for Background Work – Heavy operations (source processing, podcast generation) must use the Surreal-Commands queue. Submit commands via CommandService.submit_command_job instead of blocking HTTP request handlers.

Contribution Workflow

Open Notebook follows a strict issue-first workflow. Follow these steps to ensure your contribution aligns with project maintainers:

  1. Open an issue describing the bug or feature, proposing a solution, and requesting assignment.
  2. Wait for maintainer labeling to ensure alignment with architecture and design principles.
  3. Fork the repository and create a feature branch (e.g., feature/add-new-graph).
  4. Implement the change following async patterns, domain-driven design, and adding comprehensive tests.
  5. Run quality checks using uv run pytest for tests and uv run ruff check . with uv run ruff format . for linting.
  6. Open a Pull Request referencing the issue number (e.g., "Fixes #123"), describing changes, and including UI screenshots if applicable.

Development Environment Setup

Clone your fork and prepare the development environment using the containerized setup defined in Dockerfile and docker-compose.yml:


# 1. Fork the repo on GitHub, then clone your fork

git clone https://github.com/<your-username>/open-notebook.git
cd open-notebook

# 2. Create a new feature branch

git checkout -b feature/add-new-graph

# 3. Make changes (e.g., add open_notebook/graphs/my_new_workflow.py)

# 4. Run the test suite to ensure nothing is broken

uv run pytest

# 5. Lint and format the code

uv run ruff check .
uv run ruff format .

# 6. Commit and push

git add .
git commit -m "feat: add new LangGraph workflow for X"
git push origin feature/add-new-graph

# 7. Open a PR on GitHub, linking the issue (e.g., "Fixes #123")

Key Implementation Patterns

Submitting Background Jobs

When adding heavy background work, submit a command to the Surreal-Commands queue rather than blocking the request. In api/routers/sources.py or similar router files:


# In an API router (e.g., api/routers/sources.py)

@router.post("/sources/{id}/process")
async def process_source(id: str, body: ProcessRequest):
    command_id = await CommandService.submit_command_job(
        app="open_notebook",
        command="process_source",
        input={"source_id": id, "options": body.options},
    )
    return {"command_id": command_id}

Working with Domain Models

All business entities are defined in open_notebook/domain/. When extending functionality, modify or create domain classes here rather than in router files. The repository layer handles persistence logic for these domain objects, ensuring clean separation between business logic and data access.

Adding LangGraph Workflows

New AI features require state-machine orchestration. Create new graph definitions in open_notebook/graphs/ following the existing patterns for source processing, chat workflows, and transformations. Wire these graphs into service classes that routers invoke, maintaining the separation between HTTP handling and business logic.

Testing and Code Quality

All new code must include unit tests in the tests/ directory covering API endpoints, graph workflows, utilities, and database interactions. The project uses Ruff for linting and formatting.

Before submitting your PR:

  • Run uv run pytest to execute the full test suite
  • Run uv run ruff check . to identify style violations
  • Run uv run ruff format . to auto-format Python files

Update documentation in docs/ when API contracts or UI behaviors change, and reference CONFIGURATION.md for environment variables and AI provider settings.

Summary

  • Open Notebook uses a three-tier architecture: Next.js frontend (port 8502), FastAPI backend (port 5055), and SurrealDB (port 8000).
  • All contributions must follow the issue-first workflow outlined in docs/7-DEVELOPMENT/contributing.md.
  • Code must be async-first, domain-driven, and use provision_langchain_model for AI calls.
  • Heavy background tasks must use CommandService.submit_command_job rather than blocking requests.
  • All PRs require tests (uv run pytest), linting (uv run ruff check .), and formatting (uv run ruff format .).

Frequently Asked Questions

Do I need to open an issue before submitting a pull request?

Yes. Open Notebook requires an issue-first workflow documented in docs/7-DEVELOPMENT/contributing.md. You must open an issue describing the bug or feature, propose a solution, and wait for a maintainer to label it before forking and creating your feature branch. This ensures alignment with the project's architecture and design principles.

What testing framework does Open Notebook use?

The project uses pytest for unit testing. Run the full test suite with uv run pytest before submitting your PR. All new code must include unit tests covering API endpoints, graph workflows, and database interactions in the tests/ directory.

How do I add support for a new AI provider?

Use the Esperanto abstraction layer in open_notebook/ai/models.py. Instead of importing provider-specific SDKs, extend the provision_langchain_model function to support the new provider. This maintains the unified interface to 8+ LLMs and embedding services currently supported.

Can I run the development environment without Docker?

While the project provides Dockerfile and docker-compose.yml for containerized development, you can run services locally. Configure connection settings in CONFIGURATION.md for the frontend (port 8502), API (port 5055), and SurrealDB (port 8000). Ensure you have uv installed for Python dependency management and task running.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →