Skip to main content

Patchling

Formerly gptdiff. Same library, same API — pip install patchling (the gptdiff package still resolves during the transition).

Natural-language code transformation, as a library. Hand Patchling a dict of files and a plain-English goal; get back a unified diff — and, via smartapply, the transformed files. It's a bounded primitive you embed inside your own software systems, not an open-ended coding agent.

from patchling import generate_diff, smartapply, build_environment

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

diff = generate_diff(build_environment(files), "Rename old_name to new_name")
updated = smartapply(diff, files)

print(updated["main.py"])

Files in, files out. No filesystem access required, no agent harness. The hard part — applying an LLM-generated diff that git apply would reject — is what smartapply solves: per-file, AI-assisted patch resolution that survives fuzzy hunks, renames, new files, and deletions.

📚 Full documentation at 255bits.github.io/patchling-py

Prefer the browser? patchling is a JavaScript port of generateDiff + smartapply — try the live demos →.

The patchling family — patchling (you are here) · patchling (browser-first JS port) · patchling-examples (live browser demos)


The Patchling family

The same primitive exists for every runtime, and it powers a real product:

Project What it is
patchling (this repo) Python library + CLI tools — PyPI
patchling Zero-dependency ESM port for browser and Node — generateDiff + smartapply on in-memory file maps
nanoodle.com Visual AI workflow editor built on patchling — no server, no signup, bring your own key. See the primitive working in production
Live demos Browser examples: LLM-edited games, 3D scenes, stream overlays, AI characters

Building for the browser? Start with patchling. Building a Python backend, pipeline, or your own agent? You're in the right repo.


Quick Start

1. Install

pip install patchling

2. Set your API key

Works with any OpenAI-compatible endpoint. Get a key at nano-gpt.com/api, or point GPTDIFF_LLM_BASE_URL at your own provider.

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

# Windows
set GPTDIFF_LLM_API_KEY=your-api-key

3. Transform files in your code

from patchling import generate_diff, smartapply, build_environment

files = {
    "models.py": "class User:\n    name = CharField()",
    "tests/test_models.py": "def test_user():\n    User(name='Test').save()",
}

diff = generate_diff(
    build_environment(files),
    "Rename the 'name' field to 'username' across all layers",
)
files = smartapply(diff, files)

The diff is plain unified-diff text — log it, review it, gate it behind approval, or apply it immediately. That's the point: your system stays in control of what changes and when.

See examples/usage_example.py for a runnable version.


Core API

  • generate_diff(environment: str, goal: str, model: str = ...) -> str — generates a unified diff implementing the goal. model defaults to the GPTDIFF_MODEL env var.
  • smartapply(diff_text: str, files: dict[str, str], model: str = ...) -> dict[str, str] — applies a diff with AI-powered conflict resolution. Handles new files, deletions, and hunks that standard patching rejects. Returns a new dict; input is not mutated.
  • build_environment(files: dict[str, str]) -> str — serializes a files dict into the environment string generate_diff expects.
  • load_project_files(path, cwd) -> dict / save_files(files, base_dir) — optional filesystem helpers for when you do want to read/write a real project (respects .gitignore and .gptignore).

Full signatures, error handling, and edge cases: API Reference.

Pipeline example — sequential transformations over an in-memory codebase:

from patchling import generate_diff, smartapply, build_environment

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

for task in [
    "Add python type annotations",
    "Convert string formatting to f-strings",
    "Update deprecated API calls",
]:
    files = smartapply(generate_diff(build_environment(files), task), files)

This is the pattern nanoodle.com runs in the browser (via patchling): each workflow node is a bounded diff→apply step over an in-memory file map, and the app never touches a server.


Choosing a Model

Reasoning models produce more accurate diffs for complex changes; fast models win for applying diffs and simple edits.

Model Best for Notes
gemini-3-pro-preview Generating diffs Recommended default
gpt-4o / claude-sonnet-4-20250514 Complex or context-sensitive changes Slower, more careful
gpt5-mini Applying diffs (smartapply) Fast and reliable — best GPTDIFF_SMARTAPPLY_MODEL
gemini-2.0-flash Simple text changes Most cost-effective
export GPTDIFF_MODEL='gemini-3-pro-preview'
export GPTDIFF_SMARTAPPLY_MODEL='gpt5-mini'

Environment variables

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

Command-Line Tools

The library also ships two CLIs for working on a real project directory.

The former command names gptdiff and gptpatch still work as aliases for patchling and patchling-apply, so existing scripts don't break.

patchling

Describe a change; Patchling scans the project (respecting .gitignore/.gptignore), generates a diff, and optionally applies it:

Command What it does
patchling "prompt" Writes prompt.txt only — preview what would be sent
patchling "prompt" --call Generates the diff into diff.patch for review
patchling "prompt" --apply Generates and applies in one step
cd your-project
patchling "Add type hints to all functions" --apply

# Target specific paths
patchling "Add logging" src/api/ src/utils/helpers.py

Useful flags: --model, --temperature, --prepend <file> (custom instructions), --image <path> (visual context), --nobeep. Full list: CLI Reference.

Because changes arrive as diffs, the CLI is git-native: review with git diff, keep with git add -p, discard with git checkout ..

patchling-apply

Applies an existing unified diff to a project — standard patch logic first, smartapply fallback when that fails:

patchling-apply path/to/diff.patch
patchling-apply --diff "<diff text>"

Options: --project-dir, --model, --max_tokens, --nobeep. Details: patchling-apply docs.

Agent loops

Because each invocation is bounded (one goal → one diff), the CLI composes into loops:

while true; do
  patchling "Add missing test cases for edge conditions" --apply
  git add -A && git commit -m "Auto-improvement $(date +%H:%M)" 2>/dev/null
  sleep 30
done

One overnight test-coverage loop took a project from 18 to 127 test cases. Recipes and guardrails: Automation Guide.


Testing

pip install -e .[test]
pytest tests/

Documentation

Docs live at 255bits.github.io/patchling-py. To preview locally:

pip install .[docs]
mkdocs serve

Related projects

MIT licensed. Built by 255labs.

Metadata

Release files for patchling 0.8.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for patchling 0.8.1
File Size Uploaded
patchling-0.8.1.tar.gz 36.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for patchling 0.8.1
File Interpreter ABI Platform
patchling-0.8.1-py3-none-any.whl Python 3 none any Details

Total release size: 61.8 kB

Release files / patchling-0.8.1.tar.gz

Download URL patchling-0.8.1.tar.gz
Size 36.3 kB
Tags Source
SHA-256 checksum
How to use checksums
ce7c2e565330534e3294a4f9e0a7fdef24ca850674eb6fdf0b58bb00dd87818c
BLAKE2b-256 checksum
How to use checksums
9c88ee05752c53616cd7c60e4b990efb7b013d0f80c33c8664d40c9c8a396d6f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.10

Release files / patchling-0.8.1-py3-none-any.whl

Download URL patchling-0.8.1-py3-none-any.whl
Size 25.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d5bdc5b20d562f6084e2bff996848955258ce5f418dc9f74bdeaf8758afc650a
BLAKE2b-256 checksum
How to use checksums
1d05f1f949a4833e4f7140011aa21ac7562e85de46ca11bbd3bad2171f5690ee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.10

Release history Release notifications | RSS feed

This release

0.8.1 This release

2 release files

0.8.0

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page