# Customizing Content Transformations in Open Notebook: A Complete Developer's Guide

> Learn to customize content transformations in Open Notebook. This guide shows developers how to use prompt templates and LangGraph state machines for structured LLM text rewriting and enrichment.

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

---

**Customizing content transformations in Open Notebook involves configuring `Transformation` records with specific prompt templates that a LangGraph state machine executes to rewrite or enrich source text through structured LLM interactions.**

Open Notebook (lfnovo/open-notebook) treats content transformation as a first-class data object, enabling developers to define precisely how raw source text should be rewritten or enriched by Large Language Models (LLMs). This architecture separates transformation logic into domain models and graph-based execution pipelines, providing granular control over text processing workflows while maintaining clean separation between configuration and execution.

## Understanding the Transformation Domain Model

The foundation of customization lies in the domain layer defined in [`open_notebook/domain/transformation.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/domain/transformation.py).

### The Transformation Record

A `Transformation` record stores the metadata and configuration required to process content. According to the source code, it includes:

- **name**: Unique identifier for the transformation
- **title**: Human-readable label
- **description**: Documentation of the transformation's purpose  
- **prompt template**: The instruction set sent to the LLM
- **apply_default**: Boolean flag indicating whether the transformation automatically applies to new sources

### DefaultPrompts Configuration

The system maintains a singleton `DefaultPrompts` record that houses the default prompt shared across all transformations. This provides base instructions that prepend user-defined prompts, ensuring consistent formatting or constraints across your transformation pipeline.

## Configuring Custom Transformation Prompts

To customize how content transforms, you modify the prompt template within your `Transformation` instance.

### Prompt Template Structure

The prompt template combines with source content at runtime. When the transformation executes, the system processes the request through the following sequence:

1. Retrieves `source.full_text` if the caller provides no explicit `input_text`
2. Prepends default transformation instructions from `DefaultPrompts`
3. Renders the final system prompt using `ai_prompter.Prompter`

### Automatic Application Behavior

Setting `apply_default=True` on a `Transformation` record configures the system to automatically apply this transformation to new sources as they are ingested. This flag controls the default pipeline behavior without requiring explicit invocation for each source.

## The Graph Execution Pipeline

Transformations execute through a LangGraph state machine defined in [`open_notebook/graphs/transformation.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/transformation.py).

### LangGraph State Machine Overview

The graph implements a structured workflow for LLM interaction. It manages the conversation flow through discrete nodes, with the transformation logic encapsulated in the `run_transformation` node function.

### The run_transformation Node

When invoked, the `run_transformation` node performs the following operations:

1. **Content Resolution**: Pulls `source.full_text` when `input_text` is not explicitly provided by the caller
2. **Prompt Assembly**: Prepends default transformation instructions to the user-supplied prompt template
3. **Template Rendering**: Uses `ai_prompter.Prompter` to render the final system prompt
4. **Model Provisioning**: Calls `provision_langchain_model` to instantiate a LangChain chain configured for the requested model ID
5. **LLM Invocation**: Sends a message payload containing `[SystemMessage, HumanMessage]` to the configured LLM
6. **Response Processing**: Extracts pure text from the LLM response, removing internal formatting markers

### Code Example: Transformation Flow

```python

# Conceptual workflow based on open_notebook/graphs/transformation.py

from open_notebook.domain.transformation import Transformation, DefaultPrompts

# Define a custom transformation with specific prompting

transformation = Transformation(
    name="summarize_technical",
    title="Technical Summarization", 
    description="Summarizes technical content for non-experts",
    prompt_template="Summarize the following text for a general audience:\n\n{content}",
    apply_default=False  # Set True for automatic application

)

# The LangGraph node handles execution automatically:

# - Retrieves source.full_text if input_text is null

# - Prepends DefaultPrompts instructions to the template

# - Renders via ai_prompter.Prompter

# - Provisions model via provision_langchain_model(model_id)

# - Returns processed text via SystemMessage/HumanMessage exchange

```

## Summary

- **Transformation records** in [`open_notebook/domain/transformation.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/domain/transformation.py) store configuration including name, prompt template, and the `apply_default` automatic application flag
- **DefaultPrompts** provides singleton-based default instructions that prepend to all transformation prompts for consistent baseline behavior
- The **LangGraph state machine** in [`open_notebook/graphs/transformation.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/transformation.py) orchestrates execution through the `run_transformation` node
- The pipeline automatically falls back to `source.full_text` when explicit `input_text` is omitted by the caller
- **Model provisioning** occurs dynamically via `provision_langchain_model` based on the requested model ID, ensuring flexible LLM backend support

## Frequently Asked Questions

### What is a transformation in Open Notebook?

A transformation is a first-class data object that defines how raw source text should be rewritten or enriched by an LLM. According to the lfnovo/open-notebook source code, it encapsulates metadata (name, title, description) and a prompt template stored in [`open_notebook/domain/transformation.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/domain/transformation.py) that instructs the model how to process content.

### How do I make a transformation apply automatically to new sources?

Set the `apply_default` boolean flag to `True` on your `Transformation` record. As implemented in [`open_notebook/domain/transformation.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/domain/transformation.py), this flag signals the ingestion pipeline to automatically apply the transformation to new sources without requiring manual invocation for each item.

### Where are transformation prompts stored?

Transformation prompts reside in two locations: the `prompt_template` field of individual `Transformation` records, and the singleton `DefaultPrompts` record containing base instructions shared across all transformations. Both are defined in [`open_notebook/domain/transformation.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/domain/transformation.py) and combined during execution in [`open_notebook/graphs/transformation.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/transformation.py).

### How does the transformation graph handle source content?

The `run_transformation` node in [`open_notebook/graphs/transformation.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/transformation.py) extracts content from `source.full_text` if the caller does not provide explicit `input_text`. It then prepends default instructions from `DefaultPrompts`, renders the prompt using `ai_prompter.Prompter`, provisions the appropriate model via `provision_langchain_model`, and processes the LLM response to extract clean text output.