Skip to content

Make changes to your project with natural language using diffs (generated and smartapplied). CLI and API available.

License

Notifications You must be signed in to change notification settings

255BITS/gptdiff

Repository files navigation

GPTDiff

Transform your codebase with natural language. GPTDiff lets you describe code changes in plain English and automatically generates and applies the diffs for you.

# Install and configure
pip install gptdiff
export GPTDIFF_LLM_API_KEY='your-api-key'  # Get one at https://nano-gpt.com/api

# Make changes with a single command
gptdiff "Add input validation to all form fields" --apply

That's it. GPTDiff reads your entire project, understands the context, generates a unified diff, and applies it—all in one command.

📚 Full documentation at gptdiff.255labs.xyz


Quick Start

Step 1: Install

pip install gptdiff

Step 2: Set Your API Key

# Linux/macOS
export GPTDIFF_LLM_API_KEY='your-api-key'

# Windows
set GPTDIFF_LLM_API_KEY=your-api-key

Get your API key at nano-gpt.com/api.

Step 3: Run Your First Command

Navigate to any project directory and describe what you want to change:

cd your-project
gptdiff "Add type hints to all functions" --apply

What happens:

  1. GPTDiff scans your codebase (respecting .gitignore)
  2. Sends context + your instruction to an AI model
  3. Receives a unified diff
  4. Applies the changes to your files

Three Ways to Use GPTDiff

Command What It Does When to Use
gptdiff "prompt" Generates prompt.txt only Preview what will be sent to the LLM
gptdiff "prompt" --call Generates diff, saves to diff.patch Review changes before applying
gptdiff "prompt" --apply Generates and applies diff automatically When you're ready to make changes

Examples:

# Just generate the prompt (no API call)
gptdiff "Improve error messages"
# → Creates prompt.txt - useful for manual LLM experimentation

# Generate diff but don't apply it
gptdiff "Add API documentation" --call
# → Creates diff.patch - review before applying

# Generate and apply in one step
gptdiff "Add button animations on press" --apply
# → Changes applied directly to your files

See It In Action

GPTDiff doesn't just run commands—it transforms your code. Here are real before/after examples:

Example 1: Add Type Hints

Command:

gptdiff "Add type hints to all functions" --apply

Before:

def calculate_total(items, tax_rate):
    subtotal = sum(item['price'] * item['quantity'] for item in items)
    return subtotal * (1 + tax_rate)

def format_currency(amount):
    return f"${amount:.2f}"

After:

def calculate_total(items: list[dict], tax_rate: float) -> float:
    subtotal = sum(item['price'] * item['quantity'] for item in items)
    return subtotal * (1 + tax_rate)

def format_currency(amount: float) -> str:
    return f"${amount:.2f}"

Example 2: Add Error Handling

Command:

gptdiff "Add try/except blocks with proper error messages to all file operations" --apply

Before:

def read_config(path):
    with open(path) as f:
        return json.load(f)

After:

def read_config(path):
    try:
        with open(path) as f:
            return json.load(f)
    except FileNotFoundError:
        raise ConfigError(f"Configuration file not found: {path}")
    except json.JSONDecodeError as e:
        raise ConfigError(f"Invalid JSON in config file {path}: {e}")

Example 3: Refactor Across Multiple Files

Command:

gptdiff "Rename the User class to Account and update all imports and references" --apply

Before (models/user.py):

class User:
    def __init__(self, name: str, email: str):
        self.name = name
        self.email = email

Before (services/auth.py):

from models.user import User

def get_current_user() -> User:
    return User("John", "[email protected]")

After (models/account.py): (file renamed)

class Account:
    def __init__(self, name: str, email: str):
        self.name = name
        self.email = email

After (services/auth.py):

from models.account import Account

def get_current_user() -> Account:
    return Account("John", "[email protected]")

GPTDiff understands your entire codebase—it updates class definitions, imports, type hints, and references across all files in one operation.


Why Choose GPTDiff?

Feature Benefit
Plain English instructions No need to learn complex refactoring tools
Full project context AI sees all your files, understands relationships
Smart conflict resolution Handles merge conflicts automatically
Git-native workflow Review changes with git diff, undo with git checkout
You control everything Preview with --call, apply only when ready

Choosing a Model

Different AI models have different strengths. Reasoning models produce more accurate results for complex refactoring but take longer. Fast models are better for simple, straightforward changes.

Model Best For Speed Notes
gemini-3-pro-preview General code changes, refactoring Fast Recommended default - great balance
gpt-4o Complex multi-file changes Medium Reliable for most tasks
claude-sonnet-4-20250514 Nuanced code understanding Medium Great for context-sensitive changes
gemini-2.0-flash Simple text changes, translations Very fast Most cost-effective option
gpt5-mini Applying diffs (smartapply) Very fast Best for GPTDIFF_SMARTAPPLY_MODEL

Quick rule: Use gemini-3-pro-preview as your default. For applying diffs, set gpt5-mini as your smartapply model.

# Recommended setup
export GPTDIFF_MODEL='gemini-3-pro-preview'
export GPTDIFF_SMARTAPPLY_MODEL='gpt5-mini'

# Use a specific model for one command
gptdiff "Convert callbacks to async/await" --model gpt-4o

Advanced Configuration

Environment Variables

Variable Purpose Default
GPTDIFF_LLM_API_KEY Your API key (required) -
GPTDIFF_MODEL Model for diff generation gemini-3-pro-preview
GPTDIFF_SMARTAPPLY_MODEL Model for applying diffs gpt5-mini
GPTDIFF_LLM_BASE_URL API endpoint https://nano-gpt.com/api/v1/

Excluding Files

Prevent files from being sent to the LLM by adding them to .gitignore or .gptignore:

# .gptignore example
*.env
secrets/
node_modules/

gptpatch: Apply Diffs Directly

gptpatch is a companion command-line tool to GPTDiff that applies unified diffs directly to your project.

Usage

Apply a diff provided directly:

gptpatch --diff "<diff text>"

Or apply a diff from a file:

gptpatch path/to/diff.patch

Options

  • --project-dir: Specify the target project directory (default: current directory)
  • --model: (Optional) Specify the LLM model for advanced conflict resolution
  • --max_tokens: (Optional) Define the maximum token count for LLM responses during patch application
  • --nobeep: Disable the completion beep notification

Workflow

gptpatch first attempts to apply the diff using standard patch logic. If that fails, it automatically falls back to a smart apply mechanism that leverages AI-powered conflict resolution.

For more details, see the gptpatch documentation on our docs site.


CLI Options Reference

Option Description
--apply Generate diff and apply it automatically
--call Generate diff and save to diff.patch (for review)
--model <name> Specify which LLM to use
--temperature <0-2> Control creativity (default: 0.7)
--nobeep Disable completion notification sound
--prepend <file> Prepend custom instructions to the prompt
--image <path> Include images for visual context

Target specific files:

gptdiff "Add logging" src/api/ src/utils/helpers.py

For the complete CLI reference, see cli.md.


Documentation

Preview API docs locally using MkDocs:

pip install .[docs]
mkdocs serve

Open http://localhost:8000 to view the documentation

Python API

Integrate GPTDiff directly into your Python workflows:

from gptdiff import generate_diff, smartapply
import os

os.environ['GPTDIFF_LLM_API_KEY'] = 'your-api-key'

# Create files dictionary
files = {"main.py": "def old_name():\n    print('Need renaming')"}

# Generate transformation diff using an environment string built from the files dictionary
environment = ""
for path, content in files.items():
    environment += f"File: {path}\nContent:\n{content}\n"

diff = generate_diff(
    environment=environment,
    goal='Rename function to new_name()',
    model='deepseek-reasoner'
)

# Apply changes safely using the files dict
updated_files = smartapply(diff, files)

print("Transformed codebase:")
print(updated_files["main.py"])

Batch Processing Example:

from gptdiff import generate_diff, smartapply

files = load_your_codebase()  # Dict of {path: content}

transformations = [
    "Add python type annotations",
    "Convert string formatting to f-strings",
    "Update deprecated API calls"
]

for task in transformations:
    files = smartapply(generate_diff(build_environment(files), task), files)

Integration Note: GPTDiff leverages the AI Agent Toolbox for seamless tool usage across AI models and frameworks, making it ideal for both single responses and complex agent workflows.

Core Functions

  • generate_diff(environment: str, goal: str, model: str) -> str
    Generates a git diff implementing the requested changes

    model parameter defaults to GPTDIFF_MODEL environment variable

  • smartapply(diff_text: str, environment_str: str, model: str) -> str
    Applies complex diffs while preserving file context

Testing

To run the test suite:

pip install -e .[test]
pytest tests/

This will execute all unit tests verifying core diff generation and application logic.

plangptdiff: Generate plan prompts that call GPTDiff

plangptdiff scans your repo with ripgrep, selects only the files likely to change (always including anything named schema), and writes a ready‑to‑paste prompt to planprompt.txt:

# Prompt only
plangptdiff "add validation to the signup form"

# Prompt that will auto‑apply the diff
plangptdiff "upgrade to Django 5" --apply

The file list is appended to the generated gptdiff command so the LLM sees only the files that matter, keeping prompts lean and costs down.

About

Make changes to your project with natural language using diffs (generated and smartapplied). CLI and API available.

Resources

License

Stars

Watchers

Forks

Packages

No packages published