Skip to content

Search files

search_files

SearchFilesTool — grep-like search across project files.

Registered as search_files via the axm.tools entry point.

SearchFilesTool

Grep-like search across project files.

Searches for literal strings or regex patterns across files within a sandboxed project root. Supports glob-based file filtering. Registered as search_files via axm.tools entry point.

Source code in packages/axm-edit/src/axm_edit/tools/search_files.py
Python
class SearchFilesTool:
    """Grep-like search across project files.

    Searches for literal strings or regex patterns across files within a
    sandboxed project root. Supports glob-based file filtering.
    Registered as ``search_files`` via axm.tools entry point.
    """

    agent_hint: str = (
        "Text or regex search across files."
        " Returns matching lines with file:line context."
        " Use when ast_search can't help (comments, strings, config)."
    )

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

    def execute(
        self,
        *,
        path: str = ".",
        pattern: str | None = None,
        is_regex: bool = False,
        include: list[str] | None = None,
        **kwargs: object,
    ) -> ToolResult:
        """Search for a pattern across project files.

        Args:
            path: Project root directory (default ".").
            pattern: Search string or regex (required).
            is_regex: Treat pattern as regex (default False).
            include: Glob patterns to filter files (e.g. ["*.py"]).

        Returns:
            ToolResult with matches list (file, line, content),
            count, and truncated flag.
        """
        root_str = path

        # ── Validate inputs ──────────────────────────────────────────
        if pattern is None or pattern == "":
            return ToolResult(
                success=False,
                error="Missing required argument: pattern",
            )

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

        # Compile regex if needed
        matcher: re.Pattern[str] | str
        if is_regex:
            try:
                matcher = re.compile(pattern)
            except re.error as exc:
                return ToolResult(
                    success=False,
                    error=f"Invalid regex pattern: {exc}",
                )
        else:
            matcher = pattern

        # ── Walk and search ──────────────────────────────────────────
        results, truncated = _walk_and_search(root, matcher, is_regex, include)

        return ToolResult(
            success=True,
            data={
                "matches": results,
                "count": len(results),
                "truncated": truncated,
            },
        )
name property

Tool name used for MCP registration.

execute(*, path='.', pattern=None, is_regex=False, include=None, **kwargs)

Search for a pattern across project files.

Parameters:

Name Type Description Default
path str

Project root directory (default ".").

'.'
pattern str | None

Search string or regex (required).

None
is_regex bool

Treat pattern as regex (default False).

False
include list[str] | None

Glob patterns to filter files (e.g. ["*.py"]).

None

Returns:

Type Description
ToolResult

ToolResult with matches list (file, line, content),

ToolResult

count, and truncated flag.

Source code in packages/axm-edit/src/axm_edit/tools/search_files.py
Python
def execute(
    self,
    *,
    path: str = ".",
    pattern: str | None = None,
    is_regex: bool = False,
    include: list[str] | None = None,
    **kwargs: object,
) -> ToolResult:
    """Search for a pattern across project files.

    Args:
        path: Project root directory (default ".").
        pattern: Search string or regex (required).
        is_regex: Treat pattern as regex (default False).
        include: Glob patterns to filter files (e.g. ["*.py"]).

    Returns:
        ToolResult with matches list (file, line, content),
        count, and truncated flag.
    """
    root_str = path

    # ── Validate inputs ──────────────────────────────────────────
    if pattern is None or pattern == "":
        return ToolResult(
            success=False,
            error="Missing required argument: pattern",
        )

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

    # Compile regex if needed
    matcher: re.Pattern[str] | str
    if is_regex:
        try:
            matcher = re.compile(pattern)
        except re.error as exc:
            return ToolResult(
                success=False,
                error=f"Invalid regex pattern: {exc}",
            )
    else:
        matcher = pattern

    # ── Walk and search ──────────────────────────────────────────
    results, truncated = _walk_and_search(root, matcher, is_regex, include)

    return ToolResult(
        success=True,
        data={
            "matches": results,
            "count": len(results),
            "truncated": truncated,
        },
    )