Skip to content

Batch rollback

batch_rollback

BatchRollbackTool — restore project state to a checkpoint.

Registered as batch_rollback via the axm.tools entry point.

BatchRollbackTool

Restore project state to a previous checkpoint.

Registered as batch_rollback via axm.tools entry point.

Source code in packages/axm-edit/src/axm_edit/tools/batch_rollback.py
Python
class BatchRollbackTool:
    """Restore project state to a previous checkpoint.

    Registered as ``batch_rollback`` via axm.tools entry point.
    """

    agent_hint: str = (
        "Undo a batch_edit. Pass back the full checkpoint snapshot payload"
        " from the batch_edit response verbatim (a JSON string, not a hash)."
    )

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

    def execute(self, **kwargs: object) -> ToolResult:
        """Rollback to a checkpoint created by batch_edit.

        Args:
            **kwargs: Keyword arguments.
                path: Project root directory.
                checkpoint: The snapshot payload from batch_edit's response.

        Returns:
            ToolResult indicating whether the rollback succeeded.
        """
        raw_path = kwargs.get("path", ".")
        path = raw_path if isinstance(raw_path, str) else "."
        raw_checkpoint = kwargs.get("checkpoint")
        checkpoint = raw_checkpoint if isinstance(raw_checkpoint, str) else None

        if not checkpoint:
            return ToolResult(
                success=False,
                error="checkpoint is required",
            )

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

            files = _restored_files(checkpoint)
            success = rollback(root, checkpoint).ok
            error = None if success else "Rollback failed"
            return ToolResult(
                success=success,
                data={"restored": success},
                error=error,
                text=render_text(
                    success=success,
                    checkpoint=checkpoint,
                    files=files,
                    error=error,
                ),
            )
        except (OSError, ValueError) as exc:
            return ToolResult(success=False, error=str(exc))
name property

Tool name used for MCP registration.

execute(**kwargs)

Rollback to a checkpoint created by batch_edit.

Parameters:

Name Type Description Default
**kwargs object

Keyword arguments. path: Project root directory. checkpoint: The snapshot payload from batch_edit's response.

{}

Returns:

Type Description
ToolResult

ToolResult indicating whether the rollback succeeded.

Source code in packages/axm-edit/src/axm_edit/tools/batch_rollback.py
Python
def execute(self, **kwargs: object) -> ToolResult:
    """Rollback to a checkpoint created by batch_edit.

    Args:
        **kwargs: Keyword arguments.
            path: Project root directory.
            checkpoint: The snapshot payload from batch_edit's response.

    Returns:
        ToolResult indicating whether the rollback succeeded.
    """
    raw_path = kwargs.get("path", ".")
    path = raw_path if isinstance(raw_path, str) else "."
    raw_checkpoint = kwargs.get("checkpoint")
    checkpoint = raw_checkpoint if isinstance(raw_checkpoint, str) else None

    if not checkpoint:
        return ToolResult(
            success=False,
            error="checkpoint is required",
        )

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

        files = _restored_files(checkpoint)
        success = rollback(root, checkpoint).ok
        error = None if success else "Rollback failed"
        return ToolResult(
            success=success,
            data={"restored": success},
            error=error,
            text=render_text(
                success=success,
                checkpoint=checkpoint,
                files=files,
                error=error,
            ),
        )
    except (OSError, ValueError) as exc:
        return ToolResult(success=False, error=str(exc))

render_text(*, success, checkpoint, files, error)

Render a compact, LLM-facing view of a rollback outcome.

The header carries the global status — when the working tree was restored, otherwise so a failed/no-op rollback is impossible to miss — alongside the restored-file count. (The checkpoint is an opaque JSON snapshot payload, not a short hash, so it is not summarised in the header.) Every restored file is then listed verbatim, one per line. On failure the header surfaces the error, so nothing carried in data (the restored flag) or the error is lost: only JSON structure is dropped.

Source code in packages/axm-edit/src/axm_edit/tools/batch_rollback.py
Python
def render_text(
    *,
    success: bool,
    checkpoint: str,
    files: list[str],
    error: str | None,
) -> str:
    """Render a compact, LLM-facing view of a rollback outcome.

    The header carries the global status — ``✓`` when the working tree was
    restored, ``✗`` otherwise so a failed/no-op rollback is impossible to
    miss — alongside the restored-file count. (The checkpoint is an opaque
    JSON snapshot payload, not a short hash, so it is not summarised in the
    header.) Every restored file is then listed verbatim, one per line. On
    failure the header surfaces the error, so nothing carried in ``data``
    (the ``restored`` flag) or the error is lost: only JSON structure is
    dropped.
    """
    del checkpoint  # opaque payload, not summarisable — kept for signature parity
    if success:
        n = len(files)
        plural = "s" if n != 1 else ""
        header = f"batch_rollback | ✓ | {n} file{plural} restored"
        return "\n".join([header, *files])
    reason = error or "nothing restored"
    header = f"batch_rollback | ✗ | {reason}"
    return "\n".join([header, *files])