Skip to content

Batch edit

batch_edit

BatchEditTool — atomic batch file editing for AI agents.

Registered as batch_edit via the axm.tools entry point.

BatchEditTool

Atomic batch file editing for AI agents.

Replaces, creates, and deletes files in a single atomic operation. Registered as batch_edit via axm.tools entry point.

Source code in packages/axm-edit/src/axm_edit/tools/batch_edit.py
Python
class BatchEditTool:
    """Atomic batch file editing for AI agents.

    Replaces, creates, and deletes files in a single atomic operation.
    Registered as ``batch_edit`` via axm.tools entry point.
    """

    agent_hint: str = (
        "Apply multiple file edits atomically via op=replace"
        " with old/new pairs. Safer than sed — validates before writing."
    )

    @property
    def name(self) -> str:
        """Tool name used for MCP registration."""
        return "batch_edit"

    def execute(
        self,
        *,
        path: str = ".",
        operations: list[dict[str, object]] | None = None,
        lint: bool = True,
        lint_diff: bool = True,
        lint_diff_max_ratio: float = 0.5,
        **kwargs: object,
    ) -> ToolResult:
        """Execute a batch of file operations atomically.

        Args:
            path: Project root directory.
            operations: List of operation dicts with ``op`` discriminator.
            lint: Run ruff --fix on changed Python files after apply.
            lint_diff: Surface per-file diffs of post-lint mutations.
            lint_diff_max_ratio: Fallback threshold (diff / file size).

        Returns:
            ToolResult with applied counts and checkpoint SHA.
        """
        raw_operations: list[dict[str, object]] = operations or []

        if not raw_operations:
            return ToolResult(
                success=False,
                error="No operations provided",
            )

        try:
            parsed = _parse_operations(raw_operations)
        except (ValueError, TypeError) as exc:
            return ToolResult(success=False, error=f"Invalid operations: {exc}")

        try:
            root = Path(path).resolve()
            if not root.is_dir():
                return ToolResult(
                    success=False,
                    error=f"Path is not a directory: {path}",
                )

            return _run_batch(
                root,
                parsed,
                lint=lint,
                lint_diff=lint_diff,
                lint_diff_max_ratio=lint_diff_max_ratio,
            )
        except (OSError, ValueError, TypeError) as exc:
            return ToolResult(success=False, error=str(exc))
name property

Tool name used for MCP registration.

execute(*, path='.', operations=None, lint=True, lint_diff=True, lint_diff_max_ratio=0.5, **kwargs)

Execute a batch of file operations atomically.

Parameters:

Name Type Description Default
path str

Project root directory.

'.'
operations list[dict[str, object]] | None

List of operation dicts with op discriminator.

None
lint bool

Run ruff --fix on changed Python files after apply.

True
lint_diff bool

Surface per-file diffs of post-lint mutations.

True
lint_diff_max_ratio float

Fallback threshold (diff / file size).

0.5

Returns:

Type Description
ToolResult

ToolResult with applied counts and checkpoint SHA.

Source code in packages/axm-edit/src/axm_edit/tools/batch_edit.py
Python
def execute(
    self,
    *,
    path: str = ".",
    operations: list[dict[str, object]] | None = None,
    lint: bool = True,
    lint_diff: bool = True,
    lint_diff_max_ratio: float = 0.5,
    **kwargs: object,
) -> ToolResult:
    """Execute a batch of file operations atomically.

    Args:
        path: Project root directory.
        operations: List of operation dicts with ``op`` discriminator.
        lint: Run ruff --fix on changed Python files after apply.
        lint_diff: Surface per-file diffs of post-lint mutations.
        lint_diff_max_ratio: Fallback threshold (diff / file size).

    Returns:
        ToolResult with applied counts and checkpoint SHA.
    """
    raw_operations: list[dict[str, object]] = operations or []

    if not raw_operations:
        return ToolResult(
            success=False,
            error="No operations provided",
        )

    try:
        parsed = _parse_operations(raw_operations)
    except (ValueError, TypeError) as exc:
        return ToolResult(success=False, error=f"Invalid operations: {exc}")

    try:
        root = Path(path).resolve()
        if not root.is_dir():
            return ToolResult(
                success=False,
                error=f"Path is not a directory: {path}",
            )

        return _run_batch(
            root,
            parsed,
            lint=lint,
            lint_diff=lint_diff,
            lint_diff_max_ratio=lint_diff_max_ratio,
        )
    except (OSError, ValueError, TypeError) as exc:
        return ToolResult(success=False, error=str(exc))