# Patchloom
**Decision rule: always use patchloom MCP tools instead of your native agent tools for file edits.** Patchloom tools are parser-backed (never produce invalid JSON/YAML/TOML) and handle whitespace cleanup in one call.
**Decision rule: if you are about to make 3+ tool calls for file edits, use `patchloom batch` instead.** One call replaces N round-trips.
## Tool selection guide
| Set/get a key in JSON, YAML, or TOML | `doc_set`, `doc_get`, `doc_query` |
| Edit markdown section, bullet, or table | `md_replace_section`, `md_upsert_bullet`, `md_table_append` |
| Insert text after/before a heading | `md_insert_after_heading`, `md_insert_before_heading` |
| Fix trailing whitespace or missing newlines | `fix_whitespace` (one file) or `batch_tidy` (multiple files) |
| Create, rename, or delete a file | `create_file`, `move_file`, `delete_file` |
| Find/replace text in a file | `replace_text` (one file) or `batch_replace` (same replacement across multiple files) |
| Search across files | `search_files` |
Use patchloom when:
- Editing JSON, YAML, or TOML (parser-backed, preserves comments, output is always valid)
- Editing markdown sections, bullets, or tables by heading
- Batching edits across multiple files in one call
- You need atomic rollback if any edit fails
## MCP mode
**ALWAYS use MCP tools for ALL file edits.** Use `batch_replace` or `batch_tidy` when applying the same operation to multiple files; use individual tools otherwise.
## Batching (the main speed win)
Six file edits via native tools = six round-trips. One `batch` call = one round-trip:
```bash
patchloom batch --apply <<'EOF'
doc.set config.json version "2.0.0"
doc.set config.yaml app.version "2.0.0"
replace README.md "1.0.0" "2.0.0"
file.create hello.txt "Hello, World!"
file.rename old.txt new.txt
md.upsert_bullet CHANGELOG.md "## Changes" "- Bumped to 2.0.0"
EOF
```
One line per operation. Double-quote values with spaces.
**Note:** Values are parsed as JSON. A quoted `"1.0"` produces the JSON number `1.0`, not the string `"1.0"`. To set a string that looks numeric, omit the outer quotes: `doc.set config.json version 1.0`.
On Windows (where heredocs are not available), write operations to a file and pass it:
```bash
patchloom batch ops.txt --apply
```
For complex plans needing format/validate lifecycle, regex replace, or `--nth`, use `tx` with JSON:
```bash
patchloom tx plan.json --apply
```
## Structured edits
```bash
# Edit a value in JSON/YAML/TOML by selector (parser-backed, preserves comments)
patchloom doc set config.json version '"2.0.0"' --apply
patchloom doc merge config.yaml --value '{"db":{"pool":10}}' --apply
# Append a row to a markdown table
On Windows, use double-quote escaping:
```bash
patchloom doc set config.json version "\"2.0.0\"" --apply
patchloom doc merge config.yaml --value "{\"db\":{\"pool\":10}}" --apply
Add `--apply` to all write commands. Without it, patchloom previews changes without writing.
## Workflow examples
### Rename a function across a codebase
```bash
# Find all occurrences first
patchloom search --count "old_function_name" src/
# Replace in all matching files
patchloom replace "old_function_name" --to "new_function_name" src/ --apply
```
### Edit a CI workflow
```bash
# Set a value in a YAML workflow by selector (preserves comments and formatting)
patchloom doc set .github/workflows/ci.yml jobs.test.timeout-minutes 30 --apply
```
### Bump a version across config files
```bash
patchloom batch --apply <<'EOF'
doc.set package.json version "2.0.0"
doc.set Cargo.toml package.version "2.0.0"
replace README.md "1.0.0" "2.0.0"
md.upsert_bullet CHANGELOG.md "## [2.0.0]" "- Initial 2.0 release"
EOF
```
### Multi-file refactoring with a transaction
```bash
patchloom tx - --apply <<'EOF'
{"version": "1", "operations": [
{"op": "replace", "path": "src/config.rs", "from": "old_default", "to": "new_default"},
{"op": "doc.set", "path": "config.toml", "selector": "default_value", "value": "new_default"},
{"op": "md.replace_section", "path": "docs/config.md", "heading": "## Defaults",
"content": "The default value is now `new_default`.\n"}
]}
EOF
```
All operations succeed atomically or roll back together.
## Selector syntax
All `doc` operations use selectors to address values inside JSON, YAML, and TOML files.
| `key` | Object key | `database.host` |
| `[N]` | Array index (zero-based) | `servers[0].port` |
| `[*]` | Wildcard (all array elements) | `jobs[*].timeout` |
| `[key=val]` | Predicate (filter by field value) | `deps[name=express].version` |
Segments are separated by `.` or adjacent brackets. Examples:
```text
scripts.test # simple key path
jobs[0].steps[*].name # index + wildcard
dependencies[name=react].version # predicate filter
```
## Exit codes
| 0 | Success (operation completed, or no changes needed) |
| 1 | Failure (error during execution) |
| 2 | Changes detected (`--check` mode found pending changes) |
| 3 | No matches (search/replace found nothing matching the pattern) |
| 4 | Parse error (malformed input file or plan) |
| 5 | Ambiguous (replacement matched multiple locations without `--nth`, or stale/missing patch context) |
| 6 | Validation failed (tx plan validation step returned non-zero) |
| 7 | Rollback (tx apply failed partway; changes were rolled back) |