Skip to main content

Natural-language code transformation as a library: generate unified diffs with LLMs and apply them resiliently with smartapply. Formerly gptdiff.

Project description

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 familypatchling (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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

patchling-0.8.1.tar.gz (36.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

patchling-0.8.1-py3-none-any.whl (25.5 kB view details)

Uploaded Python 3

File details

Details for the file patchling-0.8.1.tar.gz.

File metadata

  • Download URL: patchling-0.8.1.tar.gz
  • Upload date:
  • Size: 36.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.10

File hashes

Hashes for patchling-0.8.1.tar.gz
Algorithm Hash digest
SHA256 ce7c2e565330534e3294a4f9e0a7fdef24ca850674eb6fdf0b58bb00dd87818c
MD5 c06a1570f098e239d1baa687f80f198b
BLAKE2b-256 9c88ee05752c53616cd7c60e4b990efb7b013d0f80c33c8664d40c9c8a396d6f

See more details on using hashes here.

File details

Details for the file patchling-0.8.1-py3-none-any.whl.

File metadata

  • Download URL: patchling-0.8.1-py3-none-any.whl
  • Upload date:
  • Size: 25.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.10

File hashes

Hashes for patchling-0.8.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d5bdc5b20d562f6084e2bff996848955258ce5f418dc9f74bdeaf8758afc650a
MD5 1564fac4a32c5e046cba7ba82f4602aa
BLAKE2b-256 1d05f1f949a4833e4f7140011aa21ac7562e85de46ca11bbd3bad2171f5690ee

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page