Skip to content

Grep Tool

Search file contents with regex.

Quick Example

from mamba_agents.tools import grep_search

# Search for pattern
matches = grep_search(
    pattern=r"def \w+\(",
    path="/project",
)

# With file filter
matches = grep_search(
    pattern="TODO",
    path="/src",
    file_pattern="*.py",
)

# With context lines
matches = grep_search(
    pattern="error",
    path="/logs",
    context_lines=2,
)

# Process results
for match in matches:
    print(f"{match.file}:{match.line}: {match.content}")

API Reference

grep_search(
    pattern: str,
    path: str,
    recursive: bool = True,
    file_pattern: str = "*",
    context_lines: int = 0,
    ignore_case: bool = False,
    regex: bool = True,
    max_results: int = 100,
    security: FilesystemSecurity | None = None,
) -> list[GrepMatch]

Search file contents for a pattern.

PARAMETER DESCRIPTION
pattern

Pattern to search for (string or regex).

TYPE: str

path

File or directory to search.

TYPE: str

recursive

Search directories recursively.

TYPE: bool DEFAULT: True

file_pattern

Glob pattern for files to search (e.g., "*.py").

TYPE: str DEFAULT: '*'

context_lines

Number of lines to include before/after matches.

TYPE: int DEFAULT: 0

ignore_case

Case-insensitive search.

TYPE: bool DEFAULT: False

regex

Treat pattern as regex (default: True).

TYPE: bool DEFAULT: True

max_results

Maximum number of matches to return.

TYPE: int DEFAULT: 100

security

Optional security context for path validation.

TYPE: FilesystemSecurity | None DEFAULT: None

RETURNS DESCRIPTION
list[GrepMatch]

List of GrepMatch objects.

RAISES DESCRIPTION
FileNotFoundError

If the path doesn't exist.

PermissionError

If access is denied.

Source code in src/mamba_agents/tools/grep.py
def grep_search(
    pattern: str,
    path: str,
    recursive: bool = True,
    file_pattern: str = "*",
    context_lines: int = 0,
    ignore_case: bool = False,
    regex: bool = True,
    max_results: int = 100,
    security: FilesystemSecurity | None = None,
) -> list[GrepMatch]:
    """Search file contents for a pattern.

    Args:
        pattern: Pattern to search for (string or regex).
        path: File or directory to search.
        recursive: Search directories recursively.
        file_pattern: Glob pattern for files to search (e.g., "*.py").
        context_lines: Number of lines to include before/after matches.
        ignore_case: Case-insensitive search.
        regex: Treat pattern as regex (default: True).
        max_results: Maximum number of matches to return.
        security: Optional security context for path validation.

    Returns:
        List of GrepMatch objects.

    Raises:
        FileNotFoundError: If the path doesn't exist.
        PermissionError: If access is denied.
    """
    search_path = security.validate_path(path) if security is not None else Path(path)

    if not search_path.exists():
        raise FileNotFoundError(f"Path not found: {path}")

    # Compile the pattern (escape for literal search if not regex mode)
    flags = re.IGNORECASE if ignore_case else 0
    compiled = re.compile(pattern, flags) if regex else re.compile(re.escape(pattern), flags)

    matches: list[GrepMatch] = []

    # Get files to search
    if search_path.is_file():
        files = [search_path]
    else:
        if recursive:
            files = list(search_path.rglob(file_pattern))
        else:
            files = list(search_path.glob(file_pattern))

    for file_path in files:
        if not file_path.is_file():
            continue

        if len(matches) >= max_results:
            break

        try:
            # Skip binary files
            content = file_path.read_bytes()
            if b"\x00" in content[:8192]:  # Check first 8KB for null bytes
                continue

            lines = content.decode("utf-8", errors="replace").splitlines()

            for i, line in enumerate(lines):
                if len(matches) >= max_results:
                    break

                if compiled.search(line):
                    # Get context lines
                    start = max(0, i - context_lines)
                    end = min(len(lines), i + context_lines + 1)

                    match = GrepMatch(
                        file=str(file_path),
                        line_number=i + 1,  # 1-indexed
                        line=line,
                        context_before=lines[start:i],
                        context_after=lines[i + 1 : end],
                    )
                    matches.append(match)

        except (PermissionError, OSError):
            # Skip files we can't read
            continue

    return matches