axm-edit
Atomic batch file editing for AI agents — replace, rewrite, create, and delete files in a single MCP tool call
What it does
IDE agents edit files one-at-a-time. A refactor touching 30 files = 30 tool calls — 70 % of the agent's budget goes to mechanics. axm-edit replaces all of that with 1 call: a validated, atomic batch operation with a targeted per-path checkpoint for rollback (no git involved).
Features
-
batch_edit— Replace, rewrite, create, and delete files in a single atomic operation with automatic ruff --fix (arewritereplaces a whole file byte for byte, guarded by the sha256 of the bytes currently on disk) -
file_bytes— Read-only byte-level report on a file: sha256, size and a verdict separating literal non-ASCII from textual escape sequences -
read_file— Read file content with optional line-range support -
search_files— Grep-like search across project files (literal or regex) -
write_file— Write (create or overwrite) a single file -
edit_file— Apply old/new edits to a single file -
list_dir— List files and directories with metadata (recursive, depth-limited) -
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
- Preflight —
batch_editruns the same read-only checks asbatch_edit_checkbefore any checkpoint or write: a contract error (unknown edit key, missing anchor,createon an existing path) refuses the batch with an actionable remediation, and every diagnostic is returned underdata["preflight"] - Bottom-to-top — Line edits applied in reverse order to avoid line-shift problems
- Near-miss report — A
replaceanchor that matched nothing names the closest line and marks every invisible difference (<TAB>,<SP>,<NBSP>,<LF>) instead of dumping raw text
Modules
| Module | What it provides |
|---|---|
axm_edit.core.anchor_rules |
ANCHOR_RULES_HINT — single source of truth for the replace anchor contract, composed into both tool hints and the batch_edit docstring |
axm_edit.core.engine |
batch_apply — validate-then-apply batch engine |
axm_edit.core.checkpoint |
create_checkpoint / rollback — targeted per-path snapshot safety net |
axm_edit.core.diagnostics |
explain_near_miss, closest_candidate, render_invisibles — near-miss report naming the closest window and its invisible characters |
axm_edit.models.operations |
Edit, ReplaceOp, CreateOp, DeleteOp, RewriteOp, BatchResult (incl. lint_errors, rollback_failed), RollbackResult — Pydantic models |
axm_edit.services.lint |
filter_ruff_lines — keep real ruff diagnostic lines, dropping summary noise (the post-apply lint step) |
axm_edit.services.lint_diff |
compute_lint_diffs, extract_rules_by_file — tagged plus/minus diffs between post-agent and post-lint snapshots |
axm_edit.tools |
MCP tools: BatchEditTool, BatchRollbackTool, ReadFileTool, WriteFileTool, EditFileTool, SearchFilesTool, RunCommandTool, ListDirTool, FileBytesTool |
Learn More
- Getting Started — Install and use all tools in 5 minutes
- How-To Guides — Task-oriented recipes
- MCP Tools Reference — Every tool at a glance
- API Reference — Full module documentation
- Architecture — Design decisions and module layout
axm_edit
axm-edit — Atomic batch file editing for AI agents.
Replace, create, and delete files in a single atomic operation.
Operation = Annotated[ReplaceOp | CreateOp | DeleteOp | RewriteOp, Field(discriminator='op')]
module-attribute
Discriminated union of all operation types.
BatchResult
Bases: BaseModel
Result of a batch edit operation.
Atomicity contract (see :func:axm_edit.core.engine.batch_apply):
atomicity is guaranteed at validation (all-or-nothing — a validation
error rejects the whole batch before any write); the apply phase is
best-effort with automatic rollback-to-checkpoint, so on any mid-apply
exception success is False, error is populated, checkpoint
holds the targeted snapshot, and every touched path has been restored to
its pre-batch state.
Attributes:
| Name | Type | Description |
|---|---|---|
success |
bool
|
Whether all operations were applied ( |
checkpoint |
str | None
|
Targeted-path snapshot captured before apply, usable for rollback; present whenever the apply phase was entered. |
applied |
int
|
Total number of individual edits applied. |
summary |
dict[str, int]
|
Counts of modified, created, and deleted files. |
error |
str | None
|
Human-readable error message on failure. |
details |
list[ValidationError]
|
Detailed validation errors on failure. |
Source code in packages/axm-edit/src/axm_edit/models/operations.py
CreateOp
Bases: BaseModel
Create a new file.
Fails if the file already exists unless overwrite is True.
Source code in packages/axm-edit/src/axm_edit/models/operations.py
DeleteOp
Bases: BaseModel
Delete an existing file.
Fails if the file does not exist.
Source code in packages/axm-edit/src/axm_edit/models/operations.py
Edit
Bases: BaseModel
A single line-level edit within a replace operation.
Attributes:
| Name | Type | Description |
|---|---|---|
line |
int | None
|
Optional 1-indexed line hint in the original file.
If provided, used as a starting point for searching |
old |
str
|
Expected content to find and replace (validation anchor).
May contain |
new |
str
|
Replacement content. |
Source code in packages/axm-edit/src/axm_edit/models/operations.py
ReplaceOp
Bases: BaseModel
Modify lines in an existing file.
All line numbers reference the file as originally read, before any edits are applied. The engine sorts edits bottom-to-top to avoid line-shift problems.
Source code in packages/axm-edit/src/axm_edit/models/operations.py
RollbackResult
Bases: BaseModel
Outcome of a best-effort rollback.
Rollback is a strict inverse: it only undoes what the batch did. It is
also best-effort — every captured path is attempted even if an earlier one
fails, so a partial rollback is fully observable instead of aborting
mid-loop. ok is True only when the snapshot was well-formed and
every captured path was restored.
Attributes:
| Name | Type | Description |
|---|---|---|
restored |
list[str]
|
Relative paths successfully restored to their pre-batch state. |
unrestored |
list[str]
|
Relative paths that could not be restored (a filesystem error was raised while undoing them). |
valid |
bool
|
Whether the snapshot was well-formed and parseable. |
Source code in packages/axm-edit/src/axm_edit/models/operations.py
ok
property
True iff the snapshot was valid and nothing failed to restore.
ValidationError
Bases: BaseModel
A single validation failure.
Source code in packages/axm-edit/src/axm_edit/models/operations.py
| Python | |
|---|---|
batch_apply(root, operations)
Validate and apply a batch of file operations.
Atomicity contract:
- Validation is the gate. All operations are validated first; if any
fails the batch is rejected wholesale (
success=False) before a single byte is written — a true all-or-nothing guarantee. - Apply is best-effort with automatic rollback. Once validation
passes, a targeted checkpoint of every touched path is captured and the
operations are applied. If any exception occurs mid-apply (anchor
drift, a
write_text/unlink/mkdirfailure, a permission error, …) the partial work is rolled back to that checkpoint — touched files are restored to their pre-batch bytes and batch-created files (and the empty directories created for them) are removed — and a failingBatchResultis returned. The filesystem is not made transactional at the OS level; the rollback restores only the snapshotted paths.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
root
|
Path
|
Project root directory (all paths are relative to this). |
required |
operations
|
Sequence[Operation]
|
List of replace, create, rewrite and delete operations. |
required |
Returns:
| Type | Description |
|---|---|
BatchResult
|
BatchResult with success status, a targeted-path snapshot |
BatchResult
|
( |
Source code in packages/axm-edit/src/axm_edit/core/engine.py
| Python | |
|---|---|
880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 | |
rollback(root, checkpoint)
Restore exactly the paths captured by checkpoint to their prior state.
Rollback is a strict inverse of the batch and best-effort: for each snapshotted path a file that existed is rewritten with its original bytes, a file that did not exist before is removed, and only the directories the batch itself created (recorded in the snapshot) are pruned — a pre-existing directory is never removed. Every captured path is attempted even if an earlier one fails, so a partial rollback is fully reported. No git command is run.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
root
|
Path
|
Project root directory. |
required |
checkpoint
|
str
|
The JSON snapshot returned by :func: |
required |
Returns:
| Name | Type | Description |
|---|---|---|
A |
RollbackResult
|
class: |
RollbackResult
|
paths restored and those that could not be restored. |
|
RollbackResult
|
is |
|
RollbackResult
|
a malformed snapshot yields |