patchling 0.0.1__tar.gz → 0.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- patchling-0.8.0/LICENSE.txt +10 -0
- patchling-0.8.0/PKG-INFO +260 -0
- patchling-0.8.0/README.md +223 -0
- patchling-0.8.0/patchling/__init__.py +3 -0
- patchling-0.8.0/patchling/applydiff.py +327 -0
- patchling-0.8.0/patchling/core.py +1122 -0
- patchling-0.8.0/patchling/gptpatch.py +87 -0
- patchling-0.8.0/patchling/gptsummarize.py +196 -0
- patchling-0.8.0/patchling.egg-info/PKG-INFO +260 -0
- patchling-0.8.0/patchling.egg-info/SOURCES.txt +23 -0
- patchling-0.8.0/patchling.egg-info/entry_points.txt +5 -0
- patchling-0.8.0/patchling.egg-info/requires.txt +11 -0
- patchling-0.8.0/setup.py +46 -0
- patchling-0.8.0/tests/test_applydiff.py +171 -0
- patchling-0.8.0/tests/test_applydiff_edgecases.py +185 -0
- patchling-0.8.0/tests/test_diff_parse.py +35 -0
- patchling-0.8.0/tests/test_failing_case.py +25 -0
- patchling-0.8.0/tests/test_multidiff.py +50 -0
- patchling-0.8.0/tests/test_parse_diff_per_file.py +206 -0
- patchling-0.8.0/tests/test_smartapply.py +266 -0
- patchling-0.8.0/tests/test_strip_bad_ouput.py +124 -0
- patchling-0.8.0/tests/test_swallow_reasoning.py +176 -0
- patchling-0.0.1/PKG-INFO +0 -32
- patchling-0.0.1/README.md +0 -15
- patchling-0.0.1/patchling/__init__.py +0 -15
- patchling-0.0.1/patchling.egg-info/PKG-INFO +0 -32
- patchling-0.0.1/patchling.egg-info/SOURCES.txt +0 -7
- patchling-0.0.1/pyproject.toml +0 -27
- {patchling-0.0.1 → patchling-0.8.0}/patchling.egg-info/dependency_links.txt +0 -0
- {patchling-0.0.1 → patchling-0.8.0}/patchling.egg-info/top_level.txt +0 -0
- {patchling-0.0.1 → patchling-0.8.0}/setup.cfg +0 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# We help companies adapt to the AI age through product development and consulting. 255labs.xyz
|
|
2
|
+
This is free and unencumbered software released into the public domain.
|
|
3
|
+
|
|
4
|
+
Copyright 2025 255labs.xyz
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
7
|
+
|
|
8
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
9
|
+
|
|
10
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
patchling-0.8.0/PKG-INFO
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: patchling
|
|
3
|
+
Version: 0.8.0
|
|
4
|
+
Summary: Natural-language code transformation as a library: generate unified diffs with LLMs and apply them resiliently with smartapply. Formerly gptdiff.
|
|
5
|
+
Home-page: https://github.com/255BITS/patchling-py
|
|
6
|
+
Author: 255labs
|
|
7
|
+
Project-URL: Documentation, https://patchling.255labs.xyz
|
|
8
|
+
Project-URL: Source, https://github.com/255BITS/patchling-py
|
|
9
|
+
Project-URL: Browser/Node runtime (npm), https://www.npmjs.com/package/patchling
|
|
10
|
+
Project-URL: Built with patchling (nanoodle), https://nanoodle.com
|
|
11
|
+
Keywords: patchling,smartapply,llm,diff,unified-diff,patch,code-transformation,ai,codegen,gptdiff
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE.txt
|
|
17
|
+
Requires-Dist: openai>=1.0.0
|
|
18
|
+
Requires-Dist: tiktoken>=0.5.0
|
|
19
|
+
Requires-Dist: ai-agent-toolbox<1.0,>=0.2.0
|
|
20
|
+
Provides-Extra: test
|
|
21
|
+
Requires-Dist: pytest; extra == "test"
|
|
22
|
+
Requires-Dist: pytest-mock; extra == "test"
|
|
23
|
+
Provides-Extra: docs
|
|
24
|
+
Requires-Dist: mkdocs; extra == "docs"
|
|
25
|
+
Requires-Dist: mkdocs-material; extra == "docs"
|
|
26
|
+
Dynamic: author
|
|
27
|
+
Dynamic: classifier
|
|
28
|
+
Dynamic: description
|
|
29
|
+
Dynamic: description-content-type
|
|
30
|
+
Dynamic: home-page
|
|
31
|
+
Dynamic: keywords
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
Dynamic: project-url
|
|
34
|
+
Dynamic: provides-extra
|
|
35
|
+
Dynamic: requires-dist
|
|
36
|
+
Dynamic: summary
|
|
37
|
+
|
|
38
|
+
# Patchling
|
|
39
|
+
|
|
40
|
+
> _Formerly **gptdiff**. Same library, same API — `pip install patchling` (the `gptdiff` package still resolves during the transition)._
|
|
41
|
+
|
|
42
|
+
**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.
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from patchling import generate_diff, smartapply, build_environment
|
|
46
|
+
|
|
47
|
+
files = {"main.py": "def old_name():\n print('Need renaming')\n"}
|
|
48
|
+
|
|
49
|
+
diff = generate_diff(build_environment(files), "Rename old_name to new_name")
|
|
50
|
+
updated = smartapply(diff, files)
|
|
51
|
+
|
|
52
|
+
print(updated["main.py"])
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
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.
|
|
56
|
+
|
|
57
|
+
📚 Full documentation at [patchling.255labs.xyz](https://patchling.255labs.xyz)
|
|
58
|
+
|
|
59
|
+
Prefer the browser? **[patchling](https://github.com/255BITS/patchling)** is a JavaScript port of
|
|
60
|
+
`generateDiff` + `smartapply` — try the **[live demos →](https://255bits.github.io/patchling-examples/)**.
|
|
61
|
+
|
|
62
|
+
> **The patchling family** —
|
|
63
|
+
> **patchling** (you are here) ·
|
|
64
|
+
> [**patchling**](https://github.com/255BITS/patchling) (browser-first JS port) ·
|
|
65
|
+
> [**patchling-examples**](https://github.com/255BITS/patchling-examples) (live browser demos)
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## The Patchling family
|
|
70
|
+
|
|
71
|
+
The same primitive exists for every runtime, and it powers a real product:
|
|
72
|
+
|
|
73
|
+
| Project | What it is |
|
|
74
|
+
|---------|------------|
|
|
75
|
+
| **patchling** (this repo) | Python library + CLI tools — [PyPI](https://pypi.org/project/patchling/) |
|
|
76
|
+
| **[patchling](https://github.com/255BITS/patchling)** | Zero-dependency ESM port for browser and Node — `generateDiff` + `smartapply` on in-memory file maps |
|
|
77
|
+
| **[nanoodle.com](https://nanoodle.com)** | Visual AI workflow editor built on patchling — no server, no signup, bring your own key. See the primitive working in production |
|
|
78
|
+
| **[Live demos](https://255bits.github.io/patchling-examples/)** | Browser examples: LLM-edited games, 3D scenes, stream overlays, AI characters |
|
|
79
|
+
|
|
80
|
+
Building for the browser? Start with [patchling](https://github.com/255BITS/patchling). Building a Python backend, pipeline, or your own agent? You're in the right repo.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Quick Start
|
|
85
|
+
|
|
86
|
+
### 1. Install
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pip install patchling
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 2. Set your API key
|
|
93
|
+
|
|
94
|
+
Works with any OpenAI-compatible endpoint. Get a key at [nano-gpt.com/api](https://nano-gpt.com/api), or point `GPTDIFF_LLM_BASE_URL` at your own provider.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Linux/macOS
|
|
98
|
+
export GPTDIFF_LLM_API_KEY='your-api-key'
|
|
99
|
+
|
|
100
|
+
# Windows
|
|
101
|
+
set GPTDIFF_LLM_API_KEY=your-api-key
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 3. Transform files in your code
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from patchling import generate_diff, smartapply, build_environment
|
|
108
|
+
|
|
109
|
+
files = {
|
|
110
|
+
"models.py": "class User:\n name = CharField()",
|
|
111
|
+
"tests/test_models.py": "def test_user():\n User(name='Test').save()",
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
diff = generate_diff(
|
|
115
|
+
build_environment(files),
|
|
116
|
+
"Rename the 'name' field to 'username' across all layers",
|
|
117
|
+
)
|
|
118
|
+
files = smartapply(diff, files)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
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.
|
|
122
|
+
|
|
123
|
+
See [examples/usage_example.py](examples/usage_example.py) for a runnable version.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Core API
|
|
128
|
+
|
|
129
|
+
- `generate_diff(environment: str, goal: str, model: str = ...) -> str` — generates a unified diff implementing the goal. `model` defaults to the `GPTDIFF_MODEL` env var.
|
|
130
|
+
- `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.
|
|
131
|
+
- `build_environment(files: dict[str, str]) -> str` — serializes a files dict into the environment string `generate_diff` expects.
|
|
132
|
+
- `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`).
|
|
133
|
+
|
|
134
|
+
Full signatures, error handling, and edge cases: [API Reference](https://patchling.255labs.xyz/api).
|
|
135
|
+
|
|
136
|
+
**Pipeline example** — sequential transformations over an in-memory codebase:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from patchling import generate_diff, smartapply, build_environment
|
|
140
|
+
|
|
141
|
+
files = load_your_codebase() # dict of {path: content}
|
|
142
|
+
|
|
143
|
+
for task in [
|
|
144
|
+
"Add python type annotations",
|
|
145
|
+
"Convert string formatting to f-strings",
|
|
146
|
+
"Update deprecated API calls",
|
|
147
|
+
]:
|
|
148
|
+
files = smartapply(generate_diff(build_environment(files), task), files)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
This is the pattern [nanoodle.com](https://nanoodle.com) runs in the browser (via [patchling](https://github.com/255BITS/patchling)): each workflow node is a bounded diff→apply step over an in-memory file map, and the app never touches a server.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Choosing a Model
|
|
156
|
+
|
|
157
|
+
**Reasoning models** produce more accurate diffs for complex changes; **fast models** win for applying diffs and simple edits.
|
|
158
|
+
|
|
159
|
+
| Model | Best for | Notes |
|
|
160
|
+
|-------|----------|-------|
|
|
161
|
+
| `gemini-3-pro-preview` | Generating diffs | **Recommended default** |
|
|
162
|
+
| `gpt-4o` / `claude-sonnet-4-20250514` | Complex or context-sensitive changes | Slower, more careful |
|
|
163
|
+
| `gpt5-mini` | Applying diffs (`smartapply`) | Fast and reliable — best `GPTDIFF_SMARTAPPLY_MODEL` |
|
|
164
|
+
| `gemini-2.0-flash` | Simple text changes | Most cost-effective |
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
export GPTDIFF_MODEL='gemini-3-pro-preview'
|
|
168
|
+
export GPTDIFF_SMARTAPPLY_MODEL='gpt5-mini'
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Environment variables
|
|
172
|
+
|
|
173
|
+
| Variable | Purpose | Default |
|
|
174
|
+
|----------|---------|---------|
|
|
175
|
+
| `GPTDIFF_LLM_API_KEY` | API key (required) | — |
|
|
176
|
+
| `GPTDIFF_MODEL` | Model for diff generation | `gemini-3-pro-preview` |
|
|
177
|
+
| `GPTDIFF_SMARTAPPLY_MODEL` | Model for applying diffs | `GPTDIFF_MODEL` |
|
|
178
|
+
| `GPTDIFF_LLM_BASE_URL` | OpenAI-compatible endpoint | `https://nano-gpt.com/api/v1/` |
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Command-Line Tools
|
|
183
|
+
|
|
184
|
+
The library also ships two CLIs for working on a real project directory.
|
|
185
|
+
|
|
186
|
+
> The former command names **`gptdiff`** and **`gptpatch`** still work as aliases for `patchling` and `patchling-apply`, so existing scripts don't break.
|
|
187
|
+
|
|
188
|
+
### patchling
|
|
189
|
+
|
|
190
|
+
Describe a change; Patchling scans the project (respecting `.gitignore`/`.gptignore`), generates a diff, and optionally applies it:
|
|
191
|
+
|
|
192
|
+
| Command | What it does |
|
|
193
|
+
|---------|--------------|
|
|
194
|
+
| `patchling "prompt"` | Writes `prompt.txt` only — preview what would be sent |
|
|
195
|
+
| `patchling "prompt" --call` | Generates the diff into `diff.patch` for review |
|
|
196
|
+
| `patchling "prompt" --apply` | Generates and applies in one step |
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
cd your-project
|
|
200
|
+
patchling "Add type hints to all functions" --apply
|
|
201
|
+
|
|
202
|
+
# Target specific paths
|
|
203
|
+
patchling "Add logging" src/api/ src/utils/helpers.py
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Useful flags: `--model`, `--temperature`, `--prepend <file>` (custom instructions), `--image <path>` (visual context), `--nobeep`. Full list: [CLI Reference](https://patchling.255labs.xyz/cli).
|
|
207
|
+
|
|
208
|
+
Because changes arrive as diffs, the CLI is git-native: review with `git diff`, keep with `git add -p`, discard with `git checkout .`.
|
|
209
|
+
|
|
210
|
+
### patchling-apply
|
|
211
|
+
|
|
212
|
+
Applies an existing unified diff to a project — standard patch logic first, `smartapply` fallback when that fails:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
patchling-apply path/to/diff.patch
|
|
216
|
+
patchling-apply --diff "<diff text>"
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Options: `--project-dir`, `--model`, `--max_tokens`, `--nobeep`. Details: [patchling-apply docs](https://patchling.255labs.xyz/patchling-apply).
|
|
220
|
+
|
|
221
|
+
### Agent loops
|
|
222
|
+
|
|
223
|
+
Because each invocation is bounded (one goal → one diff), the CLI composes into loops:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
while true; do
|
|
227
|
+
patchling "Add missing test cases for edge conditions" --apply
|
|
228
|
+
git add -A && git commit -m "Auto-improvement $(date +%H:%M)" 2>/dev/null
|
|
229
|
+
sleep 30
|
|
230
|
+
done
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
One overnight test-coverage loop took a project from 18 to 127 test cases. Recipes and guardrails: [Automation Guide](https://patchling.255labs.xyz/examples/automation).
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Testing
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
pip install -e .[test]
|
|
241
|
+
pytest tests/
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Documentation
|
|
245
|
+
|
|
246
|
+
Docs live at [patchling.255labs.xyz](https://patchling.255labs.xyz). To preview locally:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
pip install .[docs]
|
|
250
|
+
mkdocs serve
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Related projects
|
|
254
|
+
|
|
255
|
+
- [patchling](https://github.com/255BITS/patchling) — the browser/Node port
|
|
256
|
+
- [nanoodle.com](https://nanoodle.com) — visual AI workflow editor built on patchling
|
|
257
|
+
- [patchling live demos](https://255bits.github.io/patchling-examples/)
|
|
258
|
+
- [AI Agent Toolbox](https://github.com/255BITS/ai-agent-toolbox) — powers Patchling's tool-call parsing across models
|
|
259
|
+
|
|
260
|
+
MIT licensed. Built by [255labs](https://255labs.xyz).
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Patchling
|
|
2
|
+
|
|
3
|
+
> _Formerly **gptdiff**. Same library, same API — `pip install patchling` (the `gptdiff` package still resolves during the transition)._
|
|
4
|
+
|
|
5
|
+
**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.
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from patchling import generate_diff, smartapply, build_environment
|
|
9
|
+
|
|
10
|
+
files = {"main.py": "def old_name():\n print('Need renaming')\n"}
|
|
11
|
+
|
|
12
|
+
diff = generate_diff(build_environment(files), "Rename old_name to new_name")
|
|
13
|
+
updated = smartapply(diff, files)
|
|
14
|
+
|
|
15
|
+
print(updated["main.py"])
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
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.
|
|
19
|
+
|
|
20
|
+
📚 Full documentation at [patchling.255labs.xyz](https://patchling.255labs.xyz)
|
|
21
|
+
|
|
22
|
+
Prefer the browser? **[patchling](https://github.com/255BITS/patchling)** is a JavaScript port of
|
|
23
|
+
`generateDiff` + `smartapply` — try the **[live demos →](https://255bits.github.io/patchling-examples/)**.
|
|
24
|
+
|
|
25
|
+
> **The patchling family** —
|
|
26
|
+
> **patchling** (you are here) ·
|
|
27
|
+
> [**patchling**](https://github.com/255BITS/patchling) (browser-first JS port) ·
|
|
28
|
+
> [**patchling-examples**](https://github.com/255BITS/patchling-examples) (live browser demos)
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## The Patchling family
|
|
33
|
+
|
|
34
|
+
The same primitive exists for every runtime, and it powers a real product:
|
|
35
|
+
|
|
36
|
+
| Project | What it is |
|
|
37
|
+
|---------|------------|
|
|
38
|
+
| **patchling** (this repo) | Python library + CLI tools — [PyPI](https://pypi.org/project/patchling/) |
|
|
39
|
+
| **[patchling](https://github.com/255BITS/patchling)** | Zero-dependency ESM port for browser and Node — `generateDiff` + `smartapply` on in-memory file maps |
|
|
40
|
+
| **[nanoodle.com](https://nanoodle.com)** | Visual AI workflow editor built on patchling — no server, no signup, bring your own key. See the primitive working in production |
|
|
41
|
+
| **[Live demos](https://255bits.github.io/patchling-examples/)** | Browser examples: LLM-edited games, 3D scenes, stream overlays, AI characters |
|
|
42
|
+
|
|
43
|
+
Building for the browser? Start with [patchling](https://github.com/255BITS/patchling). Building a Python backend, pipeline, or your own agent? You're in the right repo.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
### 1. Install
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install patchling
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 2. Set your API key
|
|
56
|
+
|
|
57
|
+
Works with any OpenAI-compatible endpoint. Get a key at [nano-gpt.com/api](https://nano-gpt.com/api), or point `GPTDIFF_LLM_BASE_URL` at your own provider.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Linux/macOS
|
|
61
|
+
export GPTDIFF_LLM_API_KEY='your-api-key'
|
|
62
|
+
|
|
63
|
+
# Windows
|
|
64
|
+
set GPTDIFF_LLM_API_KEY=your-api-key
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 3. Transform files in your code
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from patchling import generate_diff, smartapply, build_environment
|
|
71
|
+
|
|
72
|
+
files = {
|
|
73
|
+
"models.py": "class User:\n name = CharField()",
|
|
74
|
+
"tests/test_models.py": "def test_user():\n User(name='Test').save()",
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
diff = generate_diff(
|
|
78
|
+
build_environment(files),
|
|
79
|
+
"Rename the 'name' field to 'username' across all layers",
|
|
80
|
+
)
|
|
81
|
+
files = smartapply(diff, files)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
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.
|
|
85
|
+
|
|
86
|
+
See [examples/usage_example.py](examples/usage_example.py) for a runnable version.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Core API
|
|
91
|
+
|
|
92
|
+
- `generate_diff(environment: str, goal: str, model: str = ...) -> str` — generates a unified diff implementing the goal. `model` defaults to the `GPTDIFF_MODEL` env var.
|
|
93
|
+
- `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.
|
|
94
|
+
- `build_environment(files: dict[str, str]) -> str` — serializes a files dict into the environment string `generate_diff` expects.
|
|
95
|
+
- `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`).
|
|
96
|
+
|
|
97
|
+
Full signatures, error handling, and edge cases: [API Reference](https://patchling.255labs.xyz/api).
|
|
98
|
+
|
|
99
|
+
**Pipeline example** — sequential transformations over an in-memory codebase:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from patchling import generate_diff, smartapply, build_environment
|
|
103
|
+
|
|
104
|
+
files = load_your_codebase() # dict of {path: content}
|
|
105
|
+
|
|
106
|
+
for task in [
|
|
107
|
+
"Add python type annotations",
|
|
108
|
+
"Convert string formatting to f-strings",
|
|
109
|
+
"Update deprecated API calls",
|
|
110
|
+
]:
|
|
111
|
+
files = smartapply(generate_diff(build_environment(files), task), files)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
This is the pattern [nanoodle.com](https://nanoodle.com) runs in the browser (via [patchling](https://github.com/255BITS/patchling)): each workflow node is a bounded diff→apply step over an in-memory file map, and the app never touches a server.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Choosing a Model
|
|
119
|
+
|
|
120
|
+
**Reasoning models** produce more accurate diffs for complex changes; **fast models** win for applying diffs and simple edits.
|
|
121
|
+
|
|
122
|
+
| Model | Best for | Notes |
|
|
123
|
+
|-------|----------|-------|
|
|
124
|
+
| `gemini-3-pro-preview` | Generating diffs | **Recommended default** |
|
|
125
|
+
| `gpt-4o` / `claude-sonnet-4-20250514` | Complex or context-sensitive changes | Slower, more careful |
|
|
126
|
+
| `gpt5-mini` | Applying diffs (`smartapply`) | Fast and reliable — best `GPTDIFF_SMARTAPPLY_MODEL` |
|
|
127
|
+
| `gemini-2.0-flash` | Simple text changes | Most cost-effective |
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
export GPTDIFF_MODEL='gemini-3-pro-preview'
|
|
131
|
+
export GPTDIFF_SMARTAPPLY_MODEL='gpt5-mini'
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Environment variables
|
|
135
|
+
|
|
136
|
+
| Variable | Purpose | Default |
|
|
137
|
+
|----------|---------|---------|
|
|
138
|
+
| `GPTDIFF_LLM_API_KEY` | API key (required) | — |
|
|
139
|
+
| `GPTDIFF_MODEL` | Model for diff generation | `gemini-3-pro-preview` |
|
|
140
|
+
| `GPTDIFF_SMARTAPPLY_MODEL` | Model for applying diffs | `GPTDIFF_MODEL` |
|
|
141
|
+
| `GPTDIFF_LLM_BASE_URL` | OpenAI-compatible endpoint | `https://nano-gpt.com/api/v1/` |
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Command-Line Tools
|
|
146
|
+
|
|
147
|
+
The library also ships two CLIs for working on a real project directory.
|
|
148
|
+
|
|
149
|
+
> The former command names **`gptdiff`** and **`gptpatch`** still work as aliases for `patchling` and `patchling-apply`, so existing scripts don't break.
|
|
150
|
+
|
|
151
|
+
### patchling
|
|
152
|
+
|
|
153
|
+
Describe a change; Patchling scans the project (respecting `.gitignore`/`.gptignore`), generates a diff, and optionally applies it:
|
|
154
|
+
|
|
155
|
+
| Command | What it does |
|
|
156
|
+
|---------|--------------|
|
|
157
|
+
| `patchling "prompt"` | Writes `prompt.txt` only — preview what would be sent |
|
|
158
|
+
| `patchling "prompt" --call` | Generates the diff into `diff.patch` for review |
|
|
159
|
+
| `patchling "prompt" --apply` | Generates and applies in one step |
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
cd your-project
|
|
163
|
+
patchling "Add type hints to all functions" --apply
|
|
164
|
+
|
|
165
|
+
# Target specific paths
|
|
166
|
+
patchling "Add logging" src/api/ src/utils/helpers.py
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Useful flags: `--model`, `--temperature`, `--prepend <file>` (custom instructions), `--image <path>` (visual context), `--nobeep`. Full list: [CLI Reference](https://patchling.255labs.xyz/cli).
|
|
170
|
+
|
|
171
|
+
Because changes arrive as diffs, the CLI is git-native: review with `git diff`, keep with `git add -p`, discard with `git checkout .`.
|
|
172
|
+
|
|
173
|
+
### patchling-apply
|
|
174
|
+
|
|
175
|
+
Applies an existing unified diff to a project — standard patch logic first, `smartapply` fallback when that fails:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
patchling-apply path/to/diff.patch
|
|
179
|
+
patchling-apply --diff "<diff text>"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Options: `--project-dir`, `--model`, `--max_tokens`, `--nobeep`. Details: [patchling-apply docs](https://patchling.255labs.xyz/patchling-apply).
|
|
183
|
+
|
|
184
|
+
### Agent loops
|
|
185
|
+
|
|
186
|
+
Because each invocation is bounded (one goal → one diff), the CLI composes into loops:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
while true; do
|
|
190
|
+
patchling "Add missing test cases for edge conditions" --apply
|
|
191
|
+
git add -A && git commit -m "Auto-improvement $(date +%H:%M)" 2>/dev/null
|
|
192
|
+
sleep 30
|
|
193
|
+
done
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
One overnight test-coverage loop took a project from 18 to 127 test cases. Recipes and guardrails: [Automation Guide](https://patchling.255labs.xyz/examples/automation).
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Testing
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
pip install -e .[test]
|
|
204
|
+
pytest tests/
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Documentation
|
|
208
|
+
|
|
209
|
+
Docs live at [patchling.255labs.xyz](https://patchling.255labs.xyz). To preview locally:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
pip install .[docs]
|
|
213
|
+
mkdocs serve
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Related projects
|
|
217
|
+
|
|
218
|
+
- [patchling](https://github.com/255BITS/patchling) — the browser/Node port
|
|
219
|
+
- [nanoodle.com](https://nanoodle.com) — visual AI workflow editor built on patchling
|
|
220
|
+
- [patchling live demos](https://255bits.github.io/patchling-examples/)
|
|
221
|
+
- [AI Agent Toolbox](https://github.com/255BITS/ai-agent-toolbox) — powers Patchling's tool-call parsing across models
|
|
222
|
+
|
|
223
|
+
MIT licensed. Built by [255labs](https://255labs.xyz).
|