AXM Edit — Atomic batch file editing for AI agents.
Project description
axm-edit
Atomic batch file editing for AI agents.
Overview
IDE agents edit files one-at-a-time. A refactor touching 30 files = 30 tool calls. The agent spends 70% of its budget on mechanics.
axm-edit replaces all of that with 1 call.
Features
- 🔧
batch_edit— Replace, create, and delete files in a single atomic operation - 📖
read_file— Read file content with optional line-range support - 🔍
search_files— Grep-like search across project files (literal or regex) - 📂
list_dir— List files and directories with metadata (recursive, depth-limited) - ✏️
write_file— Write or overwrite file content - ▶️
run_command— Execute shell commands with timeout and output truncation - ⏪
batch_rollback— Restore the exact paths a batch touched from a targeted snapshot - 🛡️ Atomic — All-or-nothing: validation runs before any file is touched
- 📐 Bottom-to-top — Line edits applied in reverse order to avoid line-shift problems
- 🔒 Safe — Path traversal blocked,
oldcontent validated, targeted path snapshot before writes
Installation
uv add axm-edit
Or as a workspace dependency in pyproject.toml:
[project]
dependencies = ["axm-edit"]
[tool.uv.sources]
axm-edit = { workspace = true }
Quick Start
from axm_edit.core.engine import batch_apply
from axm_edit.models.operations import Edit, ReplaceOp, CreateOp
from pathlib import Path
result = batch_apply(
root=Path("/my/project"),
operations=[
ReplaceOp(file="src/core.py", edits=[
Edit(line=5, old="class OldName:", new="class NewName:"),
]),
CreateOp(file="src/new.py", content='"""New module."""\n'),
],
)
print(result.summary) # {"modified": 1, "created": 1, "deleted": 0}
MCP Tools
batch_edit
Atomic batch file operations.
| Param | Type | Default | Description |
|---|---|---|---|
path |
str |
"." |
Project root directory |
operations |
list[Op] |
— | List of replace/create/delete operations |
lint |
bool |
True |
Run ruff --fix on changed Python files after apply |
lint_diff |
bool |
True |
Surface per-file lint_diffs hunks of post-lint mutations |
lint_diff_max_ratio |
float |
0.5 |
Fallback to file_reread_recommended when len(diff) > ratio * len(post) |
When lint_diff=True and ruff/harness_fix mutates any Python file, ToolResult.data["lint_diffs"] lists one entry per file: {"file", "rules": [ruff codes], "diff": "@L<n>\n-old\n+new..."}. On large rewrites the entry drops diff and carries "diff_skipped": "file_reread_recommended".
3 operation types:
replace — modify lines in an existing file
{
"op": "replace",
"file": "src/foo.py",
"edits": [
{"line": 3, "old": "import bar", "new": "import baz"},
{"line": 17, "old": "x = bar()", "new": "x = baz()"}
]
}
All line numbers reference the original file. The engine sorts edits bottom-to-top.
create — create a new file
{"op": "create", "file": "src/new.py", "content": "\"\"\"New module.\"\"\"\n"}
Fails if file exists (unless "overwrite": true).
delete — remove a file
{"op": "delete", "file": "src/old.py"}
read_file
Read file content with optional line-range support.
| Param | Type | Description |
|---|---|---|
path |
str |
Project root directory |
file |
str |
Relative path to the file |
start_line |
int? |
Optional 1-indexed start line (inclusive) |
end_line |
int? |
Optional 1-indexed end line (inclusive) |
search_files
Grep-like search across project files.
| Param | Type | Description |
|---|---|---|
path |
str |
Project root directory |
pattern |
str |
Search string or regex (required) |
is_regex |
bool? |
Treat pattern as regex (default false) |
include |
list[str]? |
Glob patterns to filter files (e.g. ["*.py"]) |
list_dir
List files and directories with metadata.
| Param | Type | Description |
|---|---|---|
path |
str |
Root directory to list (default ".") |
max_depth |
int? |
Recursion depth — 1 for immediate children only (default 1) |
run_command
Execute shell commands with timeout and output truncation.
| Param | Type | Description |
|---|---|---|
path |
str |
Project root directory |
command |
str |
Shell command string (required) |
cwd |
str? |
Working directory, relative to root |
timeout |
int? |
Timeout in seconds (default 30) |
batch_rollback
Restore the exact paths a batch touched from its snapshot.
| Param | Type | Description |
|---|---|---|
path |
str |
Project root directory |
checkpoint |
str |
Snapshot payload from the batch_edit response |
Development
This package is part of the axm-forge workspace.
git clone https://github.com/axm-protocols/axm-forge.git
cd axm-forge
uv sync --all-groups
# Run tests for this package
uv run pytest --package axm-edit
License
Apache-2.0 — © 2026 Gabriel Jarry
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file axm_edit-0.2.0.tar.gz.
File metadata
- Download URL: axm_edit-0.2.0.tar.gz
- Upload date:
- Size: 73.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a3803cee5211a7908402a0a9a85acbe1fbd25b3a0ef72d1eecf7d24c23719bf0
|
|
| MD5 |
531515535823ad5fff639fb38d64f7d9
|
|
| BLAKE2b-256 |
6a29d271cd9ef446b2c6ae5c7f9248a4c74ffebf5d61ce0f8e03d4c64ea84ce4
|
Provenance
The following attestation bundles were made for axm_edit-0.2.0.tar.gz:
Publisher:
publish.yml on axm-protocols/axm-forge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
axm_edit-0.2.0.tar.gz -
Subject digest:
a3803cee5211a7908402a0a9a85acbe1fbd25b3a0ef72d1eecf7d24c23719bf0 - Sigstore transparency entry: 1818531706
- Sigstore integration time:
-
Permalink:
axm-protocols/axm-forge@32c1ad9f2b9ba6ae156187b52b55bc058b5b80a9 -
Branch / Tag:
refs/tags/edit/v0.2.0 - Owner: https://github.com/axm-protocols
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@32c1ad9f2b9ba6ae156187b52b55bc058b5b80a9 -
Trigger Event:
push
-
Statement type:
File details
Details for the file axm_edit-0.2.0-py3-none-any.whl.
File metadata
- Download URL: axm_edit-0.2.0-py3-none-any.whl
- Upload date:
- Size: 47.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
848f8f29610da3183eaa3a981706ecc07e740e3935738baef3c5a9c042b7c774
|
|
| MD5 |
b90d0712a5ca170e0c394a6cc800b6e5
|
|
| BLAKE2b-256 |
f61c6f5be93622467351662b7708b446c8586fd8e17ac8744d7f36656f4337fd
|
Provenance
The following attestation bundles were made for axm_edit-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on axm-protocols/axm-forge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
axm_edit-0.2.0-py3-none-any.whl -
Subject digest:
848f8f29610da3183eaa3a981706ecc07e740e3935738baef3c5a9c042b7c774 - Sigstore transparency entry: 1818531813
- Sigstore integration time:
-
Permalink:
axm-protocols/axm-forge@32c1ad9f2b9ba6ae156187b52b55bc058b5b80a9 -
Branch / Tag:
refs/tags/edit/v0.2.0 - Owner: https://github.com/axm-protocols
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@32c1ad9f2b9ba6ae156187b52b55bc058b5b80a9 -
Trigger Event:
push
-
Statement type: