> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# AST-Grep Agent

> AST-based structural code search and rewrite tools for AI agents.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "AST-Grep Agent"
        Request[📋 User Request] --> Process[⚙️ AST-Grep Agent]
        Process --> Result[✅ Result]
    end

    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef process fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef output fill:#10B981,stroke:#7C90A0,color:#fff

    class Request input
    class Process process
    class Result output
```

> [!NOTE]
>
> **Prerequisites**
>
> * Python 3.10 or higher
> * PraisonAI Agents package installed
> * ast-grep CLI (`pip install ast-grep-cli` or `npm install -g @ast-grep/cli`)

## AST-Grep Tools

Use AST-Grep Tools to search, analyze, and rewrite code using structural patterns instead of regex.

> [!TIP]
>
> Unlike regex, AST patterns understand code structure — they won't match patterns inside comments or strings. `$VAR` captures a single node, `$$$` captures multiple nodes.

**1. Install Dependencies**

Install PraisonAI Agents and ast-grep:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
pip install praisonaiagents
pip install ast-grep-cli
```

**2. Import Components**

Import the AST-grep tools:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent
from praisonaiagents.tools import ast_grep_search, ast_grep_rewrite, ast_grep_scan
```

**3. Create Agent**

Create a code analysis agent:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
agent = Agent(
    name="CodeAnalyzer",
    instructions="Analyze and refactor code using AST patterns.",
    tools=[ast_grep_search, ast_grep_rewrite, ast_grep_scan],
)
```

**4. Run Agent**

Start the agent:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
result = agent.start("Find all async function definitions in ./src")
```

## How It Works

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant Agent
    participant Feature as AST-Grep Agent

    User->>Agent: Request
    Agent->>Feature: Process request
    Feature-->>Agent: Result
    Agent-->>User: Response
```

The user describes a refactor or search; the agent runs AST-grep search, rewrite, or scan tools on the codebase.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
flowchart LR
    subgraph Agent["Code Agent"]
        A[🤖 Agent]
    end

    subgraph Tools["AST-Grep Tools"]
        S[🔍 Search]
        R[✏️ Rewrite]
        SC[📋 Scan]
    end

    subgraph Code["Codebase"]
        F[Source Files]
    end

    A -->|"pattern + lang"| S
    A -->|"pattern + replacement"| R
    A -->|"rules YAML"| SC
    S --> F
    R --> F
    SC --> F

    style A fill:#8B0000,color:#fff
    style S fill:#189AB4,color:#fff
    style R fill:#189AB4,color:#fff
    style SC fill:#189AB4,color:#fff
    style F fill:#10B981,color:#fff
    classDef tool fill:#189AB4,color:#fff
    classDef agent fill:#8B0000,color:#fff
```

## Quick Start

**1. Simple Usage**

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent
from praisonaiagents.tools import ast_grep_search

agent = Agent(
    name="CodeSearcher",
    instructions="Search code for structural patterns.",
    tools=[ast_grep_search],
)

result = agent.start("Find all function definitions in ./src")
```

**2. With Configuration**

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent
from praisonaiagents.tools import ast_grep_search, ast_grep_rewrite

agent = Agent(
    name="Refactorer",
    instructions="Search and refactor code patterns.",
    tools=[ast_grep_search, ast_grep_rewrite],
)

result = agent.start("Rename all instances of \"old_function\" to \"new_function\" in Python files under ./src")
```

***

## Available Functions

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.tools import ast_grep_search
from praisonaiagents.tools import ast_grep_rewrite
from praisonaiagents.tools import ast_grep_scan
from praisonaiagents.tools import get_ast_grep_tools
from praisonaiagents.tools import is_ast_grep_available
```

## Function Details

### ast\_grep\_search(pattern, lang, path=".", json\_output=True)

Searches code using AST patterns. Returns structured JSON results.

| Parameter | Type | Default | Description |
| - | - | - | - |
| `pattern` | `str` | required | AST pattern (`$VAR` = single node, `$$$` = multiple) |
| `lang` | `str` | required | Language: `python`, `javascript`, `typescript`, `rust`, `go`, `java`, `c`, `cpp` |
| `path` | `str` | `"."` | File or directory to search |
| `json_output` | `bool` | `True` | Return JSON format |

> [!NOTE]
>
> A path that starts with `-` (e.g. `-my-dir`) is passed as a literal path, not a flag. The tool inserts `--` before the path in the `sg` argv.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Find all Python function definitions
result = ast_grep_search("def $FN($$$)", lang="python", path="./src")

# Find all console.log calls in JavaScript
result = ast_grep_search("console.log($$$)", lang="javascript")

# Find all async functions
result = ast_grep_search("async def $FN($$$)", lang="python")

# Find all class definitions with inheritance
result = ast_grep_search("class $NAME($BASE):", lang="python")
```

### ast\_grep\_rewrite(pattern, replacement, lang, path=".", dry\_run=True)

Rewrites code matching an AST pattern. **Dry-run by default** (shows changes without modifying files).

| Parameter | Type | Default | Description |
| - | - | - | - |
| `pattern` | `str` | required | AST pattern to match |
| `replacement` | `str` | required | Replacement pattern (can reference `$VAR` captures) |
| `lang` | `str` | required | Programming language |
| `path` | `str` | `"."` | File or directory |
| `dry_run` | `bool` | `True` | Preview only — set `False` to apply |

#### Return values

| Case | Return string |
| - | - |
| Real rewrite applied (`dry_run=False`) | `Applied N changes` (from `sg`'s stderr receipt) |
| Preview only (`dry_run=True`) with matches | `[DRY RUN] <sg output>` |
| Pattern matched nothing, `dry_run=True` | `No matches found for rewrite` |
| Pattern matched nothing, `dry_run=False` | `No changes made` |
| `sg` exited non-zero | `Error: <stderr or stdout>` |

> [!TIP]
>
> The `Applied N changes` receipt confirms that files were rewritten. `No changes made` now really means nothing was written — trust both messages.

> [!WARNING]
>
> Setting `dry_run=False` will modify files in place. Always preview first with the default `dry_run=True`.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Preview: rename a function (dry run)
result = ast_grep_rewrite(
    "def old_name($$$)",
    "def new_name($$$)",
    lang="python",
    path="./src"
)

# Actually apply: replace console.log with logger.info
result = ast_grep_rewrite(
    "console.log($MSG)",
    "logger.info($MSG)",
    lang="javascript",
    dry_run=False
)
```

### ast\_grep\_scan(path=".", rule\_file=None)

Scans code using YAML-based lint rules.

| Parameter | Type | Default | Description |
| - | - | - | - |
| `path` | `str` | `"."` | File or directory to scan |
| `rule_file` | `str` | `None` | Path to YAML rule file (uses `sgconfig.yml` if not set) |

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Scan with default rules
result = ast_grep_scan(path="./src")

# Scan with custom rules
result = ast_grep_scan(path="./src", rule_file="./rules/security.yml")
```

***

## Path Confinement

`path` and `rule_file` are constrained to the current workspace. Anything that resolves outside is rejected before `sg` runs — no destructive rewrite can escape the project.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
flowchart LR
    In[📥 path arg] --> Check{🛡️ inside workspace?}
    Check -->|yes| Run[⚙️ sg runs]
    Check -->|no| Reject[❌ Error: outside the workspace]

    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef gate fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef ok fill:#10B981,stroke:#7C90A0,color:#fff
    classDef bad fill:#8B0000,stroke:#7C90A0,color:#fff

    class In input
    class Check gate
    class Run ok
    class Reject bad
```

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.tools import ast_grep_search, ast_grep_rewrite, ast_grep_scan

# Rejected — absolute path outside the workspace
ast_grep_search("def $F($$$)", lang="python", path="/etc")
# -> "Error: path '/etc' is outside the workspace"

# Rejected — traversal outside the workspace
ast_grep_rewrite("a", "b", lang="python", path="../outside", dry_run=False)
# -> "Error: path '../outside' is outside the workspace"

# Rejected — rule file outside the workspace
ast_grep_scan(path=".", rule_file="/tmp/rules.yml")
# -> "Error: rule_file '/tmp/rules.yml' is outside the workspace"
```

> [!WARNING]
>
> If you previously passed absolute paths or `..`-traversal paths to reach sibling projects, those calls now return an error. Run the tools from inside the workspace you want to touch.

***

## Output Limits

Each call returns at most **10,000 characters**. When `sg` produces more (millions of matches against a big tree are common), the full buffer is written to a workspace-local artifact and the returned string is a head + tail preview plus an unmissable pointer.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
flowchart LR
    Out[📤 sg output] --> Cap{📏 ≤ 10,000 chars?}
    Cap -->|yes| Pass[✅ returned unchanged]
    Cap -->|no| Spill[⚙️ write full buffer to artifact]
    Spill --> Pointer[✅ head + tail + Full output saved to: path]

    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef gate fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef ok fill:#10B981,stroke:#7C90A0,color:#fff
    classDef proc fill:#189AB4,stroke:#7C90A0,color:#fff

    class Out input
    class Cap gate
    class Spill proc
    class Pass ok
    class Pointer ok
```

| Situation | What the agent sees |
| - | - |
| Output ≤ 10,000 chars | The full output, unchanged |
| Output > 10,000 chars | Head + tail preview, the word `truncated`, and a line `Full output saved to: <path>` |

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.tools import ast_grep_search

result = ast_grep_search("def $F($$$)", lang="python", path=".")
# For a huge tree the tail of `result` looks like:
# ...
# Full output saved to: .praisonai_tool_output/ast_grep_search-<id>.txt

# The advertised path is inside the workspace, so the agent's read_file / grep
# tools can open it directly to inspect the full buffer.
```

| Env var | Effect |
| - | - |
| `PRAISONAI_TOOL_OUTPUT_DIR` | When set, spill artifacts land here instead of the default `.praisonai_tool_output/` under the workspace root |

***

## Autonomy Mode

AST-grep tools are automatically included when using autonomy mode:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

# Tools auto-included via get_autonomy_default_tools()
agent = Agent(autonomy=True)
agent.start("Refactor the codebase to use consistent naming")
```

> [!TIP]
>
> In autonomy mode, ast-grep tools are available without explicit `tools=` — the agent can use them whenever it decides to search or rewrite code.

***

## Graceful Fallback

AST-grep tools work safely even when ast-grep is **not installed**:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.tools import is_ast_grep_available, ast_grep_search

# Check availability
if is_ast_grep_available():
    result = ast_grep_search("def $FN($$$)", lang="python")
else:
    print("ast-grep not installed")

# Or just call it — returns helpful install instructions
result = ast_grep_search("def $FN($$$)", lang="python")
# If not installed, returns:
# "ast-grep is not installed or not available in PATH.
#  To install: pip install ast-grep-cli"
```

> [!NOTE]
>
> Agents with ast-grep tools will **never crash** if ast-grep is missing. The tools return install instructions instead.

***

## Pattern Syntax

| Pattern | Meaning | Example |
| - | - | - |
| `$VAR` | Match single AST node | `def $FN()` matches any no-arg function |
| `$$$` | Match multiple nodes | `def $FN($$$)` matches any function |
| Literal code | Match exactly | `print("hello")` matches that exact call |

### Pattern Examples by Language

> **Python**
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> # All function definitions
> "def $FN($$$)"
>
> # All class definitions
> "class $NAME($$$):"
>
> # All if statements
> "if $COND: $$$"
>
> # All async functions
> "async def $FN($$$)"
>
> # All list comprehensions
> "[$EXPR for $VAR in $ITER]"
> ```

> **JavaScript / TypeScript**
>
> ```javascript theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> // All arrow functions
> "($$$) => $BODY"
>
> // All console.log calls
> "console.log($$$)"
>
> // All async functions
> "async function $FN($$$) { $$$ }"
>
> // All React useState hooks
> "const [$STATE, $SETTER] = useState($$$)"
>
> // All fetch calls
> "fetch($URL, $$$)"
> ```

> **Rust**
>
> ```rust theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> // All function definitions
> "fn $FN($$$) -> $RET { $$$ }"
>
> // All impl blocks
> "impl $TYPE { $$$ }"
>
> // All match expressions
> "match $EXPR { $$$ }"
>
> // All unsafe blocks
> "unsafe { $$$ }"
> ```

***

## Examples

> **Security Audit Agent**
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> from praisonaiagents import Agent, Task, AgentTeam
> from praisonaiagents.tools import ast_grep_search, ast_grep_scan
>
> security_agent = Agent(
>     name="SecurityAuditor",
>     instructions="""Audit code for security vulnerabilities:
>     - Find eval() and exec() calls
>     - Find SQL string concatenation
>     - Find hardcoded credentials""",
>     tools=[ast_grep_search, ast_grep_scan],
> )
>
> audit_task = Task(
>     description="Audit ./src for security issues: eval/exec usage, SQL injection, hardcoded secrets.",
>     expected_output="Security report with findings and recommendations.",
>     agent=security_agent,
>     name="security_audit"
> )
>
> team = AgentTeam(agents=[security_agent], tasks=[audit_task], process="sequential")
> team.start()
> ```

> **Code Migration Agent**
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> from praisonaiagents import Agent
> from praisonaiagents.tools import ast_grep_search, ast_grep_rewrite
>
> migrator = Agent(
>     name="Migrator",
>     instructions="""Migrate code patterns:
>     - Replace deprecated APIs with new ones
>     - Always preview first (dry_run=True)
>     - Only apply changes after confirming the preview""",
>     tools=[ast_grep_search, ast_grep_rewrite],
> )
>
> result = migrator.start(
>     "Replace all console.log calls with logger.info in JavaScript files under ./app"
> )
> ```

> **Multi-Agent Code Review**
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> from praisonaiagents import Agent, Task, AgentTeam
> from praisonaiagents.tools import ast_grep_search, ast_grep_scan
>
> # Searcher finds patterns
> searcher = Agent(
>     name="PatternFinder",
>     instructions="Find code patterns and anti-patterns using AST search.",
>     tools=[ast_grep_search],
> )
>
> # Reviewer analyzes findings
> reviewer = Agent(
>     name="CodeReviewer",
>     instructions="Review code quality findings and provide recommendations.",
> )
>
> search_task = Task(
>     description="Find all functions longer than 50 lines and deeply nested conditionals.",
>     agent=searcher,
>     name="pattern_search"
> )
>
> review_task = Task(
>     description="Review the search findings and provide refactoring recommendations.",
>     agent=reviewer,
>     name="code_review"
> )
>
> team = AgentTeam(
>     agents=[searcher, reviewer],
>     tasks=[search_task, review_task],
>     process="sequential"
> )
> team.start()
> ```

***

## Dependencies

| Package | Required | Install |
| - | - | - |
| `praisonaiagents` | Yes | `pip install praisonaiagents` |
| `ast-grep-cli` | Optional | `pip install ast-grep-cli` or `npm install -g @ast-grep/cli` |

> [!NOTE]
>
> Install the optional autonomy extras for ast-grep + other autonomy tools:
>
> ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> pip install praisonaiagents[autonomy]
> ```

## Error Handling

All functions return errors as strings — they never crash the agent:

* **Not installed** — returns install instructions (unchanged).
* **Empty pattern / empty replacement** — returns a clear error string (unchanged).
* **Path outside the workspace** — returns `Error: path '<value>' is outside the workspace`. See [Path Confinement](#path-confinement).
* **Rule file outside the workspace** (scan) — returns `Error: rule_file '<value>' is outside the workspace`.
* **Non-zero exit from `sg`** — returns `Error: <stderr or stdout>` (broadened from stderr-only).
* **No matches (search / scan)** — returns `No matches found` / `No issues found`.
* **No matches (rewrite)** — `No matches found for rewrite` (`dry_run=True`) or `No changes made` (`dry_run=False`).
* **Rewrite applied** — returns `sg`'s stderr receipt, e.g. `Applied N changes`.
* **Timeout** — 60s for search, 120s for rewrite and scan.
* **Output > 10,000 chars** — bounded preview plus `Full output saved to: <path>` pointer. See [Output Limits](#output-limits).

## Related

> **[Shell Tools](https://praison.ai/docs/tools/shell_tools.md)**
>
> Execute shell commands

> **[Python Tools](https://praison.ai/docs/tools/python_tools.md)**
>
> Execute Python code

> **[File Tools](https://praison.ai/docs/tools/file_tools.md)**
>
> File system operations

> **[Security](https://praison.ai/docs/best-practices/security.md)**
>
> Security best practices


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.