Releases · patchloom/patchloom · GitHub
Skip to content

Releases: patchloom/patchloom

patchloom: v0.9.0

Choose a tag to compare

@patchloom-release patchloom-release released this 01 Jul 22:27
4749549

Patchloom 0.9.0

This release closes parity gaps across all three channels (CLI, MCP, library API) and fixes a security-relevant path traversal bypass. 3 new features, 6 bug fixes, and 54 new tests across 19 commits.

Highlights

Fuzzy edit matching, context-anchored replacements, and the prepend operation each had one channel missing. This release fills all the gaps: fuzzy fallback reaches the library API, context anchoring reaches both the CLI and library API, and prepend reaches the CLI. Every replacement feature is now available in all three channels. A path traversal bypass in the containment module was also identified and patched, hardening the security boundary for all channels.

New features

  • Fuzzy fallback for replace_in_content (library API parity). The in-memory replace API now accepts fuzzy: true in ReplaceOptions. When exact match fails, patchloom automatically tries Jaro-Winkler similarity matching, then returns suggestions if fuzzy also fails. This eliminates ~15 lines of manual fallback glue that library embedders previously needed. The tx engine (CLI, MCP, and plans) already had this capability. (#1292)
  • before_context / after_context for replace (CLI and library API parity). Anchor text that disambiguates which match to target when a pattern appears multiple times in a file. The MCP replace_text tool and tx plans already supported these fields; this release adds CLI flags (--before-context, --after-context) and exposes them in the library API's ReplaceOptions. Supports fuzzy anchor matching as a fallback. (#1290, #1310)
  • prepend command (CLI parity). New CLI command that prepends content to the beginning of an existing file. The MCP prepend_file tool and library file_prepend API already existed; this completes the CLI surface. Accepts --content or --stdin (mutually exclusive). (#1290)

Bug fixes

  • Path traversal bypass in containment. canonicalize_or_ancestor silently dropped .. components from non-existent path segments, allowing paths like workspace/nonexistent/../../outside/secret.txt to escape the workspace boundary. Fixed by adding lexical normalization of . and .. before the ancestor walk. (#1296)
  • Markdown replace-section duplicated headings. When replacement content started with the same heading being replaced, the heading appeared twice in the output. Now automatically stripped. (#1306)
  • Markdown replace-section dropped blank lines. Replacing a section's content removed the trailing blank line separator before the next heading, producing tightly packed markdown. Now preserves the original spacing. (#1307)
  • YAML doc set stripped quote styles. Setting a value on a double-quoted or single-quoted YAML scalar lost the quotes, producing a plain scalar. Now uses in-place value replacement that preserves the original quoting style. (#1283)
  • Per-extension formatters were dead code. The [format.by_extension] table in .patchloom.toml was parsed and validated but never wired through to the format runner. Now correctly discovers modified files and applies extension-specific formatters. (#1285)
  • Patch, doc, and replace exit code fixes. Creation patches no longer falsely report the target as missing; doc move rejects moving a key to its own descendant; replace preview mode returns consistent exit codes. (#1297)

Library API changes

  • Bline issues #1287, #1288, #1289. ast.rename in tx plans now supports directory paths (recursive rename across all source files); numeric dot-notation selectors (e.g., env.0.value) resolve as array indices; operation field descriptions are now included in the execute_plan JSON schema for better agent tooling. (#1291)
  • selector replaces key. The key field on doc operations has been renamed to selector for consistency with selector-based commands. Old plans using key continue to work via serde aliases. (#1293)

Internal improvements

  • Deduplicated append/prepend implementation via shared ContentPosition enum. (#1299)
  • Removed all 45 #[non_exhaustive] attributes and tightened pub to pub(crate) on write.rs internals. (#1300)
  • Extracted the agent-rules generator from the oversized cmd/mod.rs into its own module. (#1301)
  • Removed backward-compatibility serde aliases and legacy error prefixes. (#1298)
  • Unified divergent parse_line_range implementations. (#1304)

Numbers

Metric v0.8.0 v0.9.0 Delta
Unit tests 1,983 2,019 +36
Integration tests 838 856 +18
PTY tests 10 10 --
Total tests 2,831 2,885 +54
CLI commands 22 23 +1
MCP tools 54 54 --
Commits -- 19 --

patchloom: v0.8.0

Choose a tag to compare

@patchloom-release patchloom-release released this 01 Jul 01:29
94df2b1

Patchloom 0.8.0

This release focuses on library API expansion, MCP usability for AI agents, and multi-language AST support. 4 new features, 3 bug fixes, and 49 new tests across 11 commits.

Highlights

Better MCP tool discovery for AI agents

AI models connected via MCP now receive a categorized tool guide in the server instructions, grouping all 54 tools into 7 categories (Document, Markdown, Text, File, AST, Plan, Server). This steers models toward doc_* tools for JSON/YAML/TOML mutations instead of falling back to verbose replace_text calls. Path parameter descriptions now explicitly state that paths are relative to the working directory, and a new server_info tool returns the server's working directory for path discovery. (#1272, #1275)

Library API for embedders

Two new public APIs let library embedders (like Bline) drop separate dependencies:

  • text_diff(original, modified, path) generates unified diffs in memory, exposing patchloom's internal diff engine as a standalone function.
  • parse_unified_diff(input) exposes patchloom's diff parser, re-exporting PatchFile, Hunk, and PatchLine types through the public API. (#1269, #1272)

Replace gains unique mode and match_count

The replace operation now supports unique: true, which fails with an error when the search pattern matches more than once. This prevents accidental multi-site replacements that corrupt files. A companion match_count field in the result reports how many matches were found, even in dry-run mode. (#1269)

New features

  • Multi-language rewrite_function_signature. The AST operation now supports all languages with tree-sitter grammars, not just Rust. Rust retains full-reconstruction logic (preserving async/unsafe/const/extern qualifiers); all other languages use surgical node replacement that preserves surrounding code exactly. (#1271)
  • server_info MCP tool. Zero-argument tool that returns the MCP server's working directory, letting agents discover the correct base path for relative file operations. (#1272)
  • text_diff and parse_unified_diff public APIs. In-memory diff generation and unified diff parsing for library embedders. (#1269, #1272)
  • unique mode and match_count for replace. Fail-safe single-match enforcement and match counting for both CLI and library API. (#1269)

Bug fixes

  • Permission-based tests no longer fail as root. Tests that set file permissions to 000 now detect when running as root (common in Docker containers) and skip gracefully instead of failing. (#1277)
  • Clarified misleading MCP code comments. Fixed a doc comment that incorrectly described validation behavior, renamed a misleading variable (log_clone to log_path), and simplified an error conversion that discarded type information. (#1278)
  • MCP no-match error signaling. Operations that find zero matches now return proper error responses instead of silent success, making failures visible to connected agents. (#1272)

Test quality

  • Replaced bare assert!(x.is_ok()) calls with .expect() for actionable panic messages on failure. (#1280)
  • Strengthened weak assertions that matched substrings too broadly (e.g., contains("a") passing on error messages). (#1279)
  • Updated clap_complete dependency for shell completion generation. (#1279)
  • Added missing MCP integration tests and corrected stale test counts in documentation. (#1262)

Numbers

Metric v0.7.0 v0.8.0 Delta
Unit tests 1,938 1,983 +45
Integration tests 834 838 +4
PTY tests 10 10 --
Total tests 2,782 2,831 +49
CLI commands 22 22 --
MCP tools 53 54 +1
Commits -- 11 --

patchloom: v0.7.0

Choose a tag to compare

@patchloom-release patchloom-release released this 30 Jun 18:38
d9d966f

Patchloom 0.7.0

The 0.7.0 release is the most thoroughly tested version of patchloom to date. 98 bug fixes from 480+ rounds of runtime testing, 15 refactoring PRs that unified the execution engine, and 9 new features. 2,782 tests (up from 1,816 in 0.6.0), 140 commits, 50,946 lines added.

Highlights

API field names aligned with LLM priors

Breaking change. CLI arguments and plan field names were renamed to match what LLMs naturally generate. Agents that previously struggled with parameter names now get them right on the first try.

Before After Why
--from / --to positional OLD + --new "replace X with Y" maps to replace X --new Y
--file positional FILE Natural first argument
hygiene tidy Clearer intent
--plan positional PLAN Direct argument

Serde aliases preserve backward compatibility for plan files: both "from" and "old" are accepted in JSON/YAML plans.

480+ rounds of runtime testing

Every command was exercised with real files, edge-case inputs, and adversarial patterns through systematic runtime testing. Combined with 12 rounds of code audit and 8 multi-perspective improvement cycles, this surfaced 98 bug fixes across all major modules.

Areas of highest bug density:

  • YAML operations: quote style preservation, comment migration after key deletion, multi-document detection, CST trailing whitespace cleanup
  • AST operations: C/C++ pointer-returning function extraction, Ruby symbol extraction, shell/bash word node handling, template interpolation traversal
  • Transaction engine: strict rollback restoring collateral files, validation step label reporting, context-filtered replace accuracy
  • Regex handling: consistent multi_line(true) across all regex builders (search, replace, tx engine, library API, AST replace), phantom EOF match filtering

Execution engine unification

All write commands now route through the transaction engine. Previously, some commands used atomic_write() directly, bypassing backup, rollback, and format/validate lifecycle steps. The unification delivered 110 new tests and eliminated a class of bugs where new commands forgot a write mode.

Three execution paths serve different needs:

Path Use case Example
execute_via_engine() Single-operation writes doc, md, create, delete, append
execute_operations() Multi-file writes with pre-filtering ast rename
execute_precomputed() Parallel scan + batch commit replace (multi-file regex)

Post-write formatter hook

New --format flag runs an external command after successful writes. Supports per-extension configuration via .patchloom.toml:

[format]
rs = "rustfmt {file}"
py = "black {file}"
go = "gofmt -w {file}"

The formatter integrates with --confirm interactive mode and transaction plans (via format steps). Format commands run after writes but before validation steps.

Symbol verification for transaction plans

Transaction plans can now include verify checks that run before and/or after operations:

{
  "verify": [
    {"symbol": "MyClass", "file": "src/lib.rs", "when": "before"},
    {"symbol": "MyClass::new", "file": "src/lib.rs", "when": "after"}
  ]
}

Pre-checks confirm symbols exist before modification. Post-checks confirm the result compiles or the expected symbols appear. Failed checks trigger rollback in strict mode.

New features

  • Windows ARM64 and Linux musl release targets (#947): Pre-built binaries now cover aarch64-pc-windows-msvc and x86_64-unknown-linux-musl.
  • tidy --dedent and --indent (#1034): Adjust indentation levels across files. --dedent 4 removes 4 spaces of leading indentation; --indent 2 adds 2 spaces.
  • AST Phase C operations (#1039, #1040): ast.insert, ast.wrap, ast.imports, ast.group, ast.reorder, ast.move, ast.extract, ast.split, and for_each glob batching.
  • Library API parity (#1047): FilePrepend, replace_in_content(), and SearchOptions with WalkBuilder support for exclude patterns and custom ignore files.
  • Template interpolation traversal (#1090): ast rename and ast refs now follow identifiers inside template literals (${varName} in JS/TS, f"{var}" in Python).
  • MCP md_dedupe_headings tool (#1097): Deduplicate repeated markdown headings in a single MCP call.

Refactoring

  • Consolidated shared logic into ops layer, separating business logic from CLI wiring (#970).
  • Extracted inline tests to companion files and organized by concern category (#1010, #1023).
  • Split cmd/mcp/mod.rs into focused submodules (#1024).
  • Routed all API write functions (AST, doc, file, replace, tidy, patch) through the tx engine (#1027-#1032).
  • Reduced DocAction and batch parsing boilerplate (#1026).
  • Extracted InsertContext struct to eliminate clippy::too_many_arguments (#1123).
  • Migrated test helpers to TxStateFixture for consistent setup (#1124).

Bug fixes (selected)

98 bug-fix commits span every major module. Selected highlights:

  • Regex anchors: ^ and $ now behave consistently across search, replace, tx engine, library API, and AST replace. All regex builders use multi_line(true). Phantom EOF matches at content.len() are filtered (#1254).
  • YAML fidelity: doc delete preserves quote styles and key order (#1239). Orphaned comments that migrate inline after key deletion are stripped (#1238). Trailing whitespace from YAML CST after key deletion is cleaned (#1237).
  • Multi-document YAML: improved detection and multi-line context matching (#1248, #1252).
  • Context-filtered replace: before/after context lines now compare multiple lines instead of single-line matching (#1248).
  • Nested predicates: doc select/delete-where predicates support nested paths (#1248).
  • Patch apply: supports file creation and deletion within unified diffs (#1235).
  • Create with empty content: create now actually creates the file instead of silently doing nothing (#1233).
  • Symlink handling: atomic_write resolves symlinks before writing (#1232).
  • Undo advancement: sequential undo now advances through backup sessions instead of replaying the same one (#1201).
  • EditorConfig: tidy check --respect-editorconfig detects EOL mismatches and honors trim_trailing_whitespace (#1199, #1203).
  • AST: C/C++ pointer-returning functions extracted correctly (#1242). Ruby gets a dedicated symbol extractor (#1241). Shell/bash word node kind included in AST rename (#1243).
  • Strict rollback: restores collateral files modified by format steps (#1116).

Test quality

  • Removed 14 duplicate test functions accumulated across audit sessions (#1255).
  • Replaced 2 dead defensive guards (unreachable through any API path) with debug_assert!() (#1255).
  • PTY test expect timeout increased from 10s to 30s to eliminate flakiness under load (#1256).
  • Replaced 19 bare assert!(x.is_ok()) with .unwrap() for proper panic messages (#955).
  • Strengthened weak contains("a") assertions that passed by matching substrings in error messages (#1125).

Dependency upgrades

  • rmcp 1.8.0 to 2.0.0 (#1221)
  • axum-server 0.7 to 0.8 (#953)
  • expectrl 0.7 to 0.9 (#953)
  • GitHub Actions group update (#971)

Numbers

Metric v0.6.0 v0.7.0 Delta
Unit tests 1,056 1,938 +882
Integration tests 750 834 +84
PTY tests 10 10 --
Total tests 1,816 2,782 +966
CLI commands 22 22 --
MCP tools 43 43 --
Bug fixes -- 98 --
Commits -- 140 --

Upgrading

The API field name changes (#1214) are the only breaking change. If you use patchloom as a library or construct plan files programmatically:

  • CLI: --from/--to are now positional OLD + --new NEW
  • Plans: serde aliases accept both old and new field names ("from" and "old" both work)
  • MCP: tool parameter names follow the new convention

No action needed if you only use the MCP server or transaction plans with the alias support.

patchloom: v0.6.0

Choose a tag to compare

@patchloom-release patchloom-release released this 25 Jun 23:16
6931ce7

Patchloom 0.6.0

The 0.6.0 release rebuilds the MCP server architecture from the ground up, adds 11 new AST tools for code-aware agent workflows, and delivers measurable performance gains for concurrent MCP workloads. 41 PRs, 112 files changed, and 1,816 tests (up from 1,678 in 0.5.0).

Highlights

MCP auto-generation: add a tool in 6 lines

The MCP server's internal architecture was redesigned around a declarative registry. 19 of the 43 tools are now auto-generated from Operation enum variants via MCP_TOOL_REGISTRY, with input schemas derived directly from Rust types using schemars. Adding a new tool that maps 1:1 to an existing operation takes 6 lines of metadata instead of a 40-line handler function.

McpToolMeta {
    tool_name: "new_tool",
    op_name: "new_op",
    description: "Short description. Example: {\"path\": \"file.txt\"}",
    has_strict: true,
    validations: &[FieldValidation::Path("path")],
},

The old mcp_tool! macro and per-tool params structs are gone. Unknown fields are rejected at the MCP layer. Schema drift between CLI operations and MCP tools is caught automatically by a new params drift test (#921).

11 AST tools for code-aware agents

All AST commands are now available as MCP tools, bringing the total from 32 to 43:

Tool What it does
ast_list List symbol definitions (functions, classes, structs) across 20 languages
ast_read Read a specific symbol's source code by name
ast_rename Rename identifiers across files (skips strings and comments)
ast_validate Check syntax and report parse errors with line numbers
ast_search Structural search using tree-sitter queries and code patterns
ast_refs Find all references to a symbol, distinguishing definitions from uses
ast_deps Extract import/dependency statements from source files
ast_map Generate a ranked repository map using PageRank over the symbol graph
ast_diff Structural diff showing added, removed, and modified symbols
ast_impact Transitive impact analysis: trace dependents through the reference graph
ast_replace Replace text only within a specific symbol's body

AST handlers are extracted into a dedicated ast_tools.rs module (633 lines), keeping mcp/mod.rs focused on infrastructure.

Performance: spawn_blocking, tree caching, PageRank convergence

Three changes improve MCP server responsiveness under concurrent load:

  • spawn_blocking for all sync I/O. Every MCP handler that touches the filesystem or runs tree-sitter parsing now executes on Tokio's blocking thread pool. This was harmless for stdio transport (single-threaded) but is critical for HTTP/HTTPS transport under concurrent requests.

  • Tree-sitter parse tree caching. Repeated AST queries against the same file reuse the cached parse tree instead of re-parsing. This is especially impactful for ast_refs and ast_impact, which traverse the same files multiple times.

  • PageRank convergence. ast_map now uses L1-norm convergence (threshold 1e-6) instead of a fixed 20 iterations. Most graphs converge in 8-12 iterations; complex ones that need more get them automatically.

Deep structural refactoring

18 refactoring PRs restructured the codebase for long-term maintainability:

  • Write-command state machine (#912): The repeated preview/check/apply/confirm branching logic was extracted into a shared state machine used by all write commands, eliminating a class of bugs where new commands forgot a mode.
  • Ops module decomposition (#911, #917): Pure data operations (doc, search) were moved from cmd/ to ops/, separating business logic from CLI wiring.
  • WritePolicy unification (#916): Two parallel WritePolicy types and the EolNormalization enum were merged into a single source of truth.
  • Schema derivation (#918, #919, #920): Operation schemas are now derived from Rust types via schemars + a central OPERATION_REGISTRY, replacing hand-maintained schema definitions.
  • Doc mutation dispatch (#888, #910): All doc_* mutations now route through a single DocMutation dispatcher with shared validation.
  • Integration test modularization (#878): The 20,935-line integration.rs monolith was split into 28 focused test modules.

Bug fixes

  • doc flatten now includes empty arrays and empty objects in output instead of silently dropping them (#897).
  • Transaction engine preserves idempotent delete semantics: deleting a file that was already removed in the same plan no longer fails (#889).
  • exit_code_to_result uses the fallback error path for all non-zero exit codes, not just known ones (#941).
  • delete_where predicates are validated before execution, catching malformed selectors early (#888).
  • search --jsonl with zero matches now returns exit code 3 (NO_MATCHES) consistently (#907).
  • ast_rename with a no-op rename (old name equals new name) returns early instead of rewriting files identically (#926).
  • Git argument injection is blocked across all commands that accept paths (#925, #926).
  • Concurrent-write warnings added to all MCP tool descriptions so agents avoid lost-update races (#908).
  • Quickstart and concepts documentation updated with missing exit code 9 (OPERATION_FAILED) and corrected ordering.

Numbers

Metric v0.5.0 v0.6.0 Delta
CLI commands 22 22 --
MCP tools 32 43 +11
Unit tests 948 1,056 +108
Integration tests 720 750 +30
PTY tests 10 10 --
Total tests 1,678 1,816 +138
PRs in this release -- 41 --
Files changed -- 112 --

Install

# Homebrew (macOS/Linux)
brew install patchloom/tap/patchloom

# crates.io
cargo install patchloom

# Pre-built binaries
# https://github.com/patchloom/patchloom/releases/latest

patchloom: v0.5.0

Choose a tag to compare

@SebTardif SebTardif released this 24 Jun 19:03
d9be9c2

Patchloom 0.5.0

The 0.5.0 release brings network-accessible MCP, a richer library API for embedders, and a major internal quality push: 55 PRs, +10,900 lines across 67 files, and 1,678 tests (up from ~1,350 in 0.4.0).

Highlights

Streamable HTTP/HTTPS transport for the MCP server

The MCP server is no longer limited to stdio. The new --http flag starts a Streamable HTTP server that any remote MCP client can connect to, bringing patchloom in line with the MCP specification's network transports.

# HTTP on localhost
patchloom mcp-server --http --port 3000

# HTTPS with TLS termination (rustls)
patchloom mcp-server --http --tls-cert cert.pem --tls-key key.pem

# Ephemeral port (OS-assigned, printed in the startup banner)
patchloom mcp-server --http --port 0

Supports graceful shutdown (Ctrl+C), configurable bind address (--host), and automatic host header restriction for loopback-only binds. Gated behind the mcp-http Cargo feature, enabled by default.

execute_plan MCP tool

Agents can now submit a full multi-operation transaction plan in a single MCP tool call instead of chaining individual calls. This is the MCP equivalent of patchloom tx and supports all 25 operation types with atomic rollback.

{
  "tool": "execute_plan",
  "arguments": {
    "plan": "op: doc.set\npath: config.yaml\nselector: version\nvalue: \"2.0.0\"\n---\nop: replace\npath: README.md\nold: \"1.0.0\"\nnew: \"2.0.0\""
  }
}

Library API for Rust embedders

Building on 0.4.0's PathGuard foundation, this release fills the remaining gaps for downstream Rust projects embedding patchloom as a library:

  • files feature: Pure file helpers (binary detection, text reading, parallel file processing) available without pulling the full CLI.
  • api::search_directory: Recursive grep-like search with full SearchOptions (glob, ignore files, context lines, multiline).
  • PlanReport return type: execute_plan now returns structured results, not just exit codes.
  • Search ignore customization: custom_ignore_filenames, exclude_patterns, and max_results across CLI, MCP, and library surfaces.
  • AST rewrite helpers: ast::rename_symbol and ast::validate_syntax available under the ast feature without cli.

Internal quality overhaul

16 refactoring PRs restructured the MCP server internals:

  • A mcp_tool! macro eliminated ~800 lines of per-handler boilerplate, with all 35 MCP tools now using a consistent pattern.
  • src/api.rs was decomposed into focused submodules.
  • Transaction execution was unified between CLI (cmd/tx) and library (src/tx) paths, sharing TxState, CachedDoc, and TxExecResult types.
  • GlobalFlags construction boilerplate was reduced across the codebase.

20 test-focused PRs added 300+ new tests and strengthened existing ones: bare .success() assertions were upgraded to .code(0), weak contains("a") substring checks were replaced with precise JSON field matches, and edge cases for MCP error paths, guard rejection, and TLS validation were added.

Bug fixes

  • HTTPS server banner now shows the actual bound port when using --port 0 (previously showed :0).
  • File MCP tools (create_file, delete_file, move_file, append_file) now route through the tx engine for structured JSON responses, consistent with all other write tools.
  • YAML nested key creation and markdown move-section body attachment fixed.
  • PathGuard::allow_temp_directory() now handles macOS /private/tmp symlink resolution.
  • Crates.io publish workflow made resilient to lock/index drift.

Numbers

Metric v0.5.0
CLI commands 22
MCP tools 35 (was 31)
Unit tests 948
Integration tests 720
PTY tests 10
Total tests 1,678
PRs in this release 55
Lines changed +10,954 / -3,864

Install

# Homebrew
brew install patchloom/tap/patchloom

# Cargo
cargo install patchloom

# Shell installer (macOS/Linux)
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/patchloom/patchloom/releases/latest/download/patchloom-installer.sh | sh

All install methods ship with every feature enabled: CLI, stdio MCP, HTTP/HTTPS MCP, and AST operations.

patchloom: v0.4.0

Choose a tag to compare

@patchloom-release patchloom-release released this 22 Jun 16:39
181c903

Patchloom 0.4.0

This is a major release focused on making Patchloom an excellent, safe, and ergonomic library for Rust applications and AI coding agents, while continuing to polish the CLI and MCP surfaces.

Highlights

PathGuard for safe library embedding

The biggest addition in 0.4.0 is first-class support for PathGuard (and the flexible AbsolutePathPolicy builder) across the entire public library API.

  • All high-level functions in patchloom::api (replace_text, doc_*, md_*, file_*, tidy, execute_plan, etc.) now accept an optional guard: Option<&PathGuard> as the final parameter.
  • execute_plan performs upfront validation using the centralized declared_paths helper.
  • The builder makes common relaxed policies easy: PathGuard::builder(root).allow_temp_directory().build().
  • Strict Reject policy, cross-file operation safety (rename, md.move_section, etc.), and symlink-aware checks are all enforced at the right time.

This was driven by real downstream usage (e.g. bline) and closes a long tail of PathGuard-related tech debt (#748#750, #755#759, #762).

Library modularity and semver safety

  • The cli feature is now optional. Use default-features = false + features = ["mcp", "ast"] (or any subset) for a dramatically smaller dependency tree when embedding Patchloom.
  • Many public types were moved to more reusable locations (ops, write, etc.) and re-exported.
  • All public structs and enums are now #[non_exhaustive] for future-proofing.

Other notable improvements

  • Shared declared_paths helper eliminates duplicated path collection logic between cmd/tx upfront guard checks and MCP validation (#762).
  • Extensive new tests for guard behavior (relaxed policies, destination rejection, cross-file operations, cfg combinations).
  • Hygiene wins: removal of now-dead TxState.guard code, direct unit coverage for the path declaration helper, stronger test assertions in several areas.
  • Numerous fixes for atomicity, confirm flows, Windows path handling, and edge cases from the recent improvement cycles.
  • Better documentation and examples for the library API surface.

Migration notes

If you were already using the library API, the new guard parameter is trailing and optional. Update call sites:

// Before
api::replace_text(path, old, new, &opts, mode)?;

// After (no guard)
api::replace_text(path, old, new, &opts, mode, None)?;

// With guard
let guard = PathGuard::builder(cwd).allow_temp_directory().build()?;
api::replace_text(path, old, new, &opts, mode, Some(&guard))?;

See the patchloom::api module documentation for full details and examples.

Thank you

Thanks to everyone who filed issues, reviewed, and used the library in real agent tooling. This release makes the "library first" story much stronger.

Full changelog and commit history are in the release PR.

patchloom: v0.3.0

Choose a tag to compare

@patchloom-release patchloom-release released this 21 Jun 04:04
9545621

Patchloom v0.3.0

This is the biggest patchloom release yet. It adds a full AST layer powered by tree-sitter, a new file.append command, post-write formatting hooks, smarter error recovery for failed edits, and a major internal cleanup.

AST-aware operations (new ast feature)

Patchloom can now parse source code. The new ast command uses tree-sitter grammars for 20 languages (Rust, Go, Python, TypeScript, JavaScript, Java, C, C++, C#, Ruby, Kotlin, Swift, Scala, PHP, Lua, Zig, Elixir, Haskell, Bash, HCL) and provides 11 subcommands:

Subcommand What it does
ast list List symbol definitions in a file or directory
ast read Read a specific symbol by name
ast rename Rename identifiers, skipping strings and comments
ast validate Check syntax of source files
ast search Structural search using tree-sitter queries
ast refs Find all references to a symbol across files
ast deps Extract import/dependency statements
ast map Generate a ranked repository map (PageRank)
ast replace Replace text only within a specific symbol's body
ast impact Transitive impact analysis of changing a symbol
ast diff Structural diff between two file versions

All subcommands support --json and --jsonl output. The ast feature is enabled by default; build with --no-default-features for a smaller binary without tree-sitter.

AST operations are also available as MCP tools (ast_list, ast_read, ast_rename, ast_validate) and in transaction plans.

Post-write formatting

All write commands (replace, create, append, md, doc, tidy, patch) now accept a --format flag that runs a shell command after a successful --apply:

patchloom replace --from "old_fn" --to "new_fn" src/main.rs \
  --apply --format "cargo fmt --all"

The formatter runs after the file is written but before the command exits, so you get a clean result in one step. A --format-timeout flag (default 30s) prevents hanging formatters. Also works through --confirm interactive mode and in transaction plans via the format lifecycle step.

file.append

New append command adds content to the end of an existing file:

patchloom append src/lib.rs --content "pub mod new_module;"
echo "new entry" | patchloom append CHANGELOG.md --stdin

Supports all standard modes (--diff, --check, --apply, --confirm), --format post-write hooks, and the --json/--jsonl output flags. Also available as the file_append MCP tool.

Smarter error recovery for edits

The fallback module, previously built but unwired, is now integrated at three levels:

  • Similarity hints. When a literal replace finds no matches, patchloom suggests similar strings using Jaro-Winkler scoring: no matches for 'proccess_data' in main.rs (did you mean: process_data?).
  • Structural validation. The MCP replace_text tool pre-validates edits to JSON, YAML, and TOML files, warning about broken syntax or unbalanced brackets before the replacement is applied.
  • Context-anchored matching. The replace_text MCP tool and transaction plans now accept optional before_context and after_context parameters. When exact matching fails, patchloom uses surrounding lines as anchors to locate the intended edit target, recovering from whitespace drift or minor formatting changes.

Word-boundary matching

New --word-boundary flag on replace prevents partial-word matches. patchloom replace --from "File" --to "Document" --word-boundary replaces SetupFile but not BenchSetupFile. Available on the CLI, in transaction plans, and via the MCP replace_text tool.

Library API for downstream consumers

The fallback and ast modules now expose their core building blocks as public API, letting library consumers (e.g., bline) use patchloom's edit recovery and tree-sitter infrastructure directly.

Fallback module (patchloom::fallback):

Function/type What it does
resolve_with_fallback() Full fallback chain: exact, anchor, similarity, structured error
anchor_match() Anchor-based matching using surrounding context lines
validate_edit() Pre-validate a replacement against JSON/YAML/TOML syntax
AnchorMatchResult Return type with matched_text, start_offset, strategy
MatchStrategy Enum: Exact, Anchor, Similarity
ValidationResult Return type with valid, errors, warnings

AST module (patchloom::ast, requires features = ["ast"]):

Function What it does
parse_source() Parse source code with tree-sitter (language detection + parser setup)
ts_language_for() Map a Language to its tree-sitter grammar
child_text_by_kind() Extract text from a child node by kind
child_text_by_kinds() Extract text from a child node matching any of several kinds

All high-level AST functions (extract_symbols, search_query, validate_source, rename_in_source, find_refs_in_source, structural_diff, compute_impact, replace_in_symbol, generate_map) were already public.

Internal cleanup

  • ops.rs split. The 4,369-line monolithic src/ops.rs was split into src/ops/{doc,md,patch,replace}.rs.
  • Transaction engine refactoring. Extracted build_full_tx_output (eliminating 6x duplication), validate_and_prepare_plan (shared validation), and execute_doc_op/execute_file_op (breaking up a 460-line match).
  • MCP validator consolidation. Unified validate_content_size/validate_param_size into a shared validate_size helper.
  • Visibility tightening. diff and exit modules narrowed to pub(crate). All 28 MCP param structs narrowed to pub(crate).
  • Dead code removal. Removed DiffResult::total_files_changed (set at 20+ sites but never read).

Breaking changes

  • diff and exit modules are no longer public. Code importing patchloom::diff::* or patchloom::exit::* must use the library API instead.
  • Operation::Replace has three new fields: word_boundary, before_context, after_context. Code constructing this variant via struct literals must include them (use ..Default::default() or add explicit values).
  • DiffResult::total_files_changed field removed.
  • Internal helper truncate_str in the fallback module narrowed from pub to pub(crate).
  • All MCP param structs narrowed from pub to pub(crate).

Test coverage

1,588 tests (887 unit + 694 integration + 7 PTY), up from 1,476 in v0.2.0.

Links

patchloom: v0.2.0

Choose a tag to compare

@patchloom-release patchloom-release released this 18 Jun 02:57
1596343

Patchloom v0.2.0

Patchloom has always been a CLI and an MCP server. Starting with this release, it is also a Rust library. This release exposes the core editing engine as a public API, hardens transaction safety, and adds three-way patch merging.

Library API

Patchloom's structured editing engine is now available as a Rust library. Add it as a dependency with no async overhead:

[dependencies]
patchloom = { version = "0.2", default-features = false }

The api module exposes doc, replace, markdown, file, and patch operations. All types are Send + Sync. Four utility modules are also public:

  • containment -- workspace path guard that prevents directory traversal attacks. Two-layer defense: syntactic depth check plus symlink-aware canonicalization.
  • exec -- shell command execution with timeout and process-tree management.
  • files -- file-walking, SIMD-accelerated binary detection, and text reading helpers.
  • write -- atomic file writes via tempfile with write-policy transformations.

All public structs and enums are marked #[non_exhaustive] for forward-compatible evolution. Cargo-semver-checks runs in CI on every release PR.

Three-way patch merge

New patch merge subcommand handles stale diffs gracefully:

# Check if a patch applies cleanly, merges cleanly, or has conflicts
patchloom patch merge stale.patch --check

# Apply with three-way merge
patchloom patch merge stale.patch --apply

# Allow conflict markers in output
patchloom patch merge stale.patch --apply --allow-conflicts

Also available in tx plans via on_stale: "merge" and allow_conflicts: true, and in the MCP server's apply_patch tool.

Conflicts produce familiar <<<<<<< patchloom (ours) / >>>>>>> patch (theirs) markers. Exit code 8 (CONFLICTS) signals unresolved conflicts.

Transaction rollback hardening

  • strict now defaults to true. Format or validation failures roll back all writes automatically. Override with "strict": false in the plan, [tx] strict = false in .patchloom.toml, or --no-strict on the CLI.
  • Mid-commit recovery. If a write fails partway through, patchloom restores already-written files from the backup session. Exit 7 for clean rollback, exit 1 if restore is incomplete.
  • Clearer exit semantics. Staging failures exit 4 (operation_failed), distinct from parse errors.

Other improvements

  • Config validation. Invalid values in .patchloom.toml (e.g., normalize_eol = "unix") now emit stderr warnings instead of silently ignoring.
  • Batch quoting docs. Expanded guidance for JSON string values in batch format, with Unix and Windows examples.
  • Schema fix. md.move_section examples in patchloom schema output now include the required op field.
  • Test coverage. 1,476 tests (807 unit + 669 integration), up from 1,300 in v0.1.7.

Breaking changes

All public structs and enums are now #[non_exhaustive]. Code that constructs these types via struct literals must add ..Default::default(). Serde deserialization (the primary construction path for plans and MCP params) is unaffected.

Links

patchloom: v0.1.7

Choose a tag to compare

@patchloom-release patchloom-release released this 16 Jun 22:53
c3edf2f

0.1.7 (2026-06-16)

Features

  • add --whole-line, --range, and --collapse-blanks to replace (#564) (5651320), closes #563
  • close #573 and #574 - complete API parity and edge case tests (#576) (d6fc1a9)
  • md.move-section -- move a heading section between files (#554) (d6f42e7), closes #553

Bug Fixes

  • improvement cycle 11 — config, schema, MCP tests, docs (#568) (ea4967b)
  • improvement cycle 11b - docs, CI hardening (#569) (5041287)
  • improvement cycle 12 - Windows CI, fuzz CI matrix (#572) (c24792f)
  • improvement cycle 13 - tests, inline refactor, error context (#575) (6208177)
  • improvement cycle 14 - strengthen weak test assertions (#577) (2ba2396)
  • make unit tests portable in Docker and pseudo-TTY environments (#579) (591b4d8)
  • md move-section same-file path detection and cross-file --check mode (#556) (da76cc5)
  • rename same-file detection via path canonicalization (#557) (a1b5573)
  • replace broken shields.io badges with gist endpoints (#578) (23b14f3)
  • update MCP bench to use individual tool calls (#570) (655a1d2)

patchloom: v0.1.6

Choose a tag to compare

@patchloom-release patchloom-release released this 08 Jun 16:35
2265070

0.1.6 (2026-06-08)

Features

  • public Rust library API with thread safety, intent format, and fallback chain (#530) (093eb8b)

Bug Fixes

  • add error context to backup restore and rename cross-device paths (#543) (69018e7)
  • ci: use App token in update-branches to trigger CI on updated PRs (#523) (e51cdae)
  • correct pinned action SHAs in docs workflow (#549) (b1fabf6)
  • improvement cycle (UTF-8 truncate, doc_set double-parse, docs freshness) (#531) (a8dffb9)
  • md silent default mode, search empty-pattern guard, strengthen assertions (#542) (45d3239)
  • md/doc --check produce stdout output and doc --json errors use structured JSON (#546) (819fb7c), closes #544 #545
  • propagate read errors in file_create and extract inline conditional (#533) (26ab09c)
  • propagate YAML serialization error and remove unnecessary borrows in ops.rs (#537) (24e67f4)
  • remove documentation field so crates.io auto-links to docs.rs (#547) (f6bbd10)