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.

🌐 Project home: patchling.app — try it live in your browser · 📚 Full documentation at 255bits.github.io/patchling-py

Prefer the browser? The same primitive ships on npm as patchling for JS (generateDiff + smartapply, zero-dependency ESM) — try the live demos →.


The Patchling family

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

Project What it is
patchling for Python (this repo) Python library + CLI tools — PyPI
patchling for JS Zero-dependency ESM package for browser and Node — generateDiff + smartapply on in-memory file maps — npm
patchling.app Project homepage with a live in-browser demo of the whole diff → smartapply loop
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 for JS. Building a Python backend, pipeline, or your own agent? You're in the right repo.


Quick Start

1. Install

pip install patchling

Verify the installed CLI version with patchling --version or patchling-apply --version.

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. Pass filter_relevant=True and task= to drop files a cheap model marks irrelevant first.
  • filter_relevant(files, task, model=..., concurrency=..., cache=...) -> FilterRelevantResult — opt-in relevance filter for large directories. Each file is sent, with the task, to a cheap OpenAI-compatible model that answers yes/no. Only the yes files are returned for generate_diff and smartapply. The default model is xiaomi/mimo-v2.6-flash (Flask recall 1.0 and ~0.8x overhead figures are UNVERIFIED). The JS counterpart is filterRelevant.
  • 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/
GPTDIFF_FILTER_MODEL Cheap model for filter_relevant xiaomi/mimo-v2.6-flash (Flask recall 1.0 / ~0.8x overhead: UNVERIFIED)

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), --filter-relevant (ask a cheap model which files to send; --filter-model picks that model), --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

MIT licensed. Built by 255labs.

Metadata

Release files for patchling 0.9.2

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.9.2
File Size Uploaded
patchling-0.9.2.tar.gz 84.2 kB Details

Built distribution (wheel)

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

Total release size: 134.7 kB

Release files / patchling-0.9.2.tar.gz

Download URL patchling-0.9.2.tar.gz
Size 84.2 kB
Tags Source
SHA-256 checksum
How to use checksums
6e645774cac75536edaf5c1b65bc74a97b04796da5a3f873610aba9715d9ca74
BLAKE2b-256 checksum
How to use checksums
96780986db9150f035d1f036b67b2e922c098cd074bffbced812b916065f20aa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

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

Download URL patchling-0.9.2-py3-none-any.whl
Size 50.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ff8681275ca69e69f36c8d329c2d8a814acc2af6df66cfdd8c5679ef5f76511d
BLAKE2b-256 checksum
How to use checksums
4f0e167709b007a0300047ae164d26bf5d4c16812a0f193233a28ce11208bfc4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release history Release notifications | RSS feed

0.9.3

2 release files

This release

0.9.2 This release

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.1

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