# How Open Notebook Implements Prompt Templating with ai_prompter and Jinja2 Templates

> Learn how Open Notebook uses ai_prompter and Jinja2 templates for prompt templating. Discover automatic format instruction injection from LangChain OutputParsers for structured LLM outputs.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: how-to-guide
- Published: 2026-06-21

---

**Open Notebook uses the ai_prompter library to render Jinja2 templates stored in the `prompts/` directory, automatically injecting format instructions from LangChain OutputParsers when structured LLM outputs are required.**

The prompt templating system in the `lfnovo/open-notebook` repository provides a flexible, file-based approach to managing LLM interactions. By combining Jinja2 templates with the `ai_prompter` library's `Prompter` class, the system separates prompt content from application logic while supporting dynamic variable injection and structured output parsing.

## Template Organization in the prompts/ Directory

All Jinja2 templates reside in the `prompts/` directory at the repository root. The system organizes templates by workflow, with each functional area (such as `ask`, `chat`, `source_chat`, and `podcast`) maintaining its own subfolder containing one or more `.jinja` files.

- **`prompts/ask/entry.jinja`** – Entry point for the Ask workflow
- **`prompts/chat/system.jinja`** – System prompts for general chat interactions
- **[`prompts/CLAUDE.md`](https://github.com/lfnovo/open-notebook/blob/main/prompts/CLAUDE.md)** – Documentation covering prompt conventions and structure

This hierarchical organization allows developers to modify LLM behavior without touching Python code, making the system maintainable for non-technical contributors.

## The ai_prompter Prompter Class

The rendering engine centers on the `Prompter` class from the `ai_prompter` library, implemented in [`open_notebook/graphs/prompt.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/prompt.py). This class wraps Jinja2's template engine and provides two instantiation modes:

**Named template loading** via `prompt_template=`:

```python
system_prompt = Prompter(prompt_template="ask/entry", parser=parser).render(data=state)

```

**Raw template strings** via `template_text=`:

```python
custom_prompt = Prompter(template_text="Hello {{ name }}").render(data={"name": "User"})

```

When using the `prompt_template` parameter, the class automatically resolves the path relative to the `prompts/` directory, loading the corresponding `.jinja` file.

## Rendering Prompts with OutputParsers

For workflows requiring structured responses, the `Prompter` class integrates with LangChain's `OutputParser` to enforce JSON schema compliance. When a parser is provided, the system automatically injects `{{ format_instructions }}` into the template context.

In [`open_notebook/graphs/ask.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/ask.py) (lines 54–57), the implementation demonstrates this pattern:

```python
from langchain.output_parsers import PydanticOutputParser

parser = PydanticOutputParser(pydantic_object=Strategy)
system_prompt = Prompter(prompt_template="ask/entry", parser=parser).render(data=state)

```

The `render()` method executes the following steps:

1. Loads the specified Jinja2 template from `prompts/ask/entry.jinja`
2. Merges the supplied `state` dictionary into the template context
3. Adds `format_instructions` to the context when a parser is present
4. Returns the fully rendered prompt string

## Integration with LangGraph Workflows

Within Open Notebook's LangGraph architecture, each node constructs its system prompt using the `Prompter` class before invoking the LLM. The typical flow follows this pattern:

1. The graph node prepares a `state` dictionary containing conversation history, document context, and user queries
2. `Prompter.render(data=state)` generates the system prompt
3. The rendered prompt combines with user messages into a LangChain message payload
4. The provisioned model receives the complete context and returns a response
5. The graph strips any markdown code fences from the LLM output before processing

This separation ensures that prompt engineering concerns remain isolated from graph orchestration logic, while the Jinja2 inheritance and inclusion features enable complex template composition.

## Summary

- **Template Storage**: All Jinja2 templates live in `prompts/` with subdirectories for each workflow (`ask`, `chat`, etc.)
- **Core Class**: The `ai_prompter.Prompter` class handles template loading and rendering in [`open_notebook/graphs/prompt.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/prompt.py)
- **Structured Output**: Passing a LangChain `OutputParser` automatically injects format instructions via the `{{ format_instructions }}` placeholder
- **Usage Pattern**: Instantiate with `prompt_template="path/to/template"` and call `.render(data=state)` to generate final prompts
- **Integration**: The system operates within LangGraph nodes, connecting template rendering to LLM execution

## Frequently Asked Questions

### Where are Jinja2 templates stored in Open Notebook?

Templates are stored in the `prompts/` directory at the repository root, with subfolders organizing files by workflow (e.g., `prompts/ask/entry.jinja`, `prompts/chat/system.jinja`). This structure is documented in [`prompts/CLAUDE.md`](https://github.com/lfnovo/open-notebook/blob/main/prompts/CLAUDE.md).

### How does ai_prompter handle structured output formatting?

When a `PydanticOutputParser` is passed to the `Prompter` constructor, the `render()` method automatically adds the parser's `format_instructions` to the template context. This inserts JSON schema requirements into the prompt without manual template editing.

### What is the difference between template_text and prompt_template parameters?

The `prompt_template` parameter loads a file from the `prompts/` directory (e.g., `"ask/entry"` resolves to `prompts/ask/entry.jinja`), while `template_text` accepts a raw Jinja2 string directly for inline or dynamically generated templates.

### Which workflows use the prompt templating system?

The system supports multiple workflows including `ask` (question answering), `chat` (conversational interface), `source_chat` (document-specific chat), and `podcast` (audio content generation), each with dedicated template subdirectories in `prompts/`.