Twig — 18 Operations for AI Agents

Twig templates render Symfony, Drupal, and Craft — the presentation layer of a large slice of the PHP web. act101 navigates blocks, extends, and includes structurally, so agents follow template inheritance to the markup that actually ships.

This page is the canonical reference an AI coding agent uses to refactor, query, and analyze Twig code through the act MCP server. 18 operations available: 0 refactor, 18 query, 0 analysis. Each operation is callable from Claude Code, Cursor, Codex, OpenCode, or any MCP-compatible agent host. Click any operation for a stable anchor link suitable for citation.

18Query

Worked Twig examples

act101 reads a Twig template's {% extends %} tag as an import declaration keeping its quoted string, each {% block %} as a block declaration, {% set %} assignments as variable, {% for %}/{% if %} as block declarations named for the loop variable or the leading condition, and {% macro %} definitions as macro. symbols covers a narrower set — block, set, for, macro, and any filter or function call like |length — but reports the block definition under kind class rather than block (that suffix isn't in the symbol-kind vocabulary), the macro under kind function, and the for-loop variable under kind variable; the {% extends %} and {% if %} tags that appeared in the skeleton have no rule in symbols.scm. The unit of structure in this grammar is the tag: an {% if %}/{% else %} pair reports one block declaration for the whole construct, keeping only the leading condition as its name. Each example below is the verbatim output of the command shown, run against the file shown. Query outputs are pretty-printed with the timing block omitted.

Read the chart's inheritance, blocks, and macro

seating-chart.twig extends a shared stadium/base.twig layout, defines a seating_chart block that sets section_count and loops sections with an {% if %}/{% else %} for sold-out status, and defines a seat_label macro.

$ act query skeleton seating-chart.twig

Before

{% extends "stadium/base.twig" %}

{% block seating_chart %}
  {% set section_count = sections|length %}
  <div class="chart">
    {% for section in sections %}
      <section class="block-{{ section.code }}">
        <h2>{{ section.name }}</h2>
        {% if section.soldOut %}
          <p class="status">Sold out</p>
        {% else %}
          <p class="status">{{ section.available }} seats available</p>
        {% endif %}
      </section>
    {% endfor %}
  </div>
{% endblock %}

{% macro seat_label(row, seat) %}
  Row {{ row }}, Seat {{ seat }}
{% endmacro %}

Output

{
    "type": "Skeleton",
    "declarations": [
        {
            "kind": "import",
            "name": "\"stadium/base.twig\"",
            "range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 1,
                    "column": 1,
                    "byte_offset": 0
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 1,
                    "column": 34,
                    "byte_offset": 33
                }
            },
            "name_range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 1,
                    "column": 12,
                    "byte_offset": 11
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 1,
                    "column": 31,
                    "byte_offset": 30
                }
            }
        },
        {
            "kind": "block",
            "name": "seating_chart",
            "range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 3,
                    "column": 1,
                    "byte_offset": 35
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 17,
                    "column": 15,
                    "byte_offset": 488
                }
            },
            "name_range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 3,
                    "column": 10,
                    "byte_offset": 44
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 3,
                    "column": 23,
                    "byte_offset": 57
                }
            }
        },
        {
            "kind": "variable",
            "name": "section_count",
            "range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 4,
                    "column": 3,
                    "byte_offset": 63
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 4,
                    "column": 44,
                    "byte_offset": 104
                }
            },
            "name_range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 4,
                    "column": 10,
                    "byte_offset": 70
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 4,
                    "column": 23,
                    "byte_offset": 83
                }
            }
        },
        {
            "kind": "block",
            "name": "section",
            "range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 6,
                    "column": 5,
                    "byte_offset": 131
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 15,
                    "column": 17,
                    "byte_offset": 464
                }
            },
            "name_range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 6,
                    "column": 12,
                    "byte_offset": 138
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 6,
                    "column": 19,
                    "byte_offset": 145
                }
            }
        },
        {
            "kind": "block",
            "name": "section.soldOut",
            "range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 9,
                    "column": 9,
                    "byte_offset": 254
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 13,
                    "column": 20,
                    "byte_offset": 430
                }
            },
            "name_range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 9,
                    "column": 15,
                    "byte_offset": 260
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 9,
                    "column": 30,
                    "byte_offset": 275
                }
            }
        },
        {
            "kind": "macro",
            "name": "seat_label",
            "range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 19,
                    "column": 1,
                    "byte_offset": 490
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 21,
                    "column": 15,
                    "byte_offset": 571
                }
            },
            "name_range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 19,
                    "column": 10,
                    "byte_offset": 499
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 19,
                    "column": 20,
                    "byte_offset": 509
                }
            }
        }
    ]
}

The skeleton reports six declarations: the {% extends %} tag as import (keeping its quoted string "stadium/base.twig"), seating_chart as block, section_count as variable, the {% for %} loop as block named section, the {% if %} as block named section.soldOut (its leading condition), and seat_label as macro.

List the block, variable, loop, and function-call symbols

section_count is set from sections|length, and the {% for %} loop binds section for each section in sections.

$ act query symbols seating-chart.twig

Before

{% extends "stadium/base.twig" %}

{% block seating_chart %}
  {% set section_count = sections|length %}
  <div class="chart">
    {% for section in sections %}
      <section class="block-{{ section.code }}">
        <h2>{{ section.name }}</h2>
        {% if section.soldOut %}
          <p class="status">Sold out</p>
        {% else %}
          <p class="status">{{ section.available }} seats available</p>
        {% endif %}
      </section>
    {% endfor %}
  </div>
{% endblock %}

{% macro seat_label(row, seat) %}
  Row {{ row }}, Seat {{ seat }}
{% endmacro %}

Output

{
    "type": "Symbols",
    "symbols": [
        {
            "name": "seating_chart",
            "kind": "class",
            "range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 3,
                    "column": 10,
                    "byte_offset": 44
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 3,
                    "column": 23,
                    "byte_offset": 57
                }
            },
            "visibility": "unknown"
        },
        {
            "name": "section_count",
            "kind": "variable",
            "range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 4,
                    "column": 10,
                    "byte_offset": 70
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 4,
                    "column": 23,
                    "byte_offset": 83
                }
            },
            "visibility": "unknown"
        },
        {
            "name": "length",
            "kind": "function",
            "range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 4,
                    "column": 35,
                    "byte_offset": 95
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 4,
                    "column": 41,
                    "byte_offset": 101
                }
            },
            "visibility": "unknown"
        },
        {
            "name": "section",
            "kind": "variable",
            "range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 6,
                    "column": 12,
                    "byte_offset": 138
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 6,
                    "column": 19,
                    "byte_offset": 145
                }
            },
            "visibility": "unknown"
        },
        {
            "name": "seat_label",
            "kind": "function",
            "range": {
                "start": {
                    "file": "seating-chart.twig",
                    "line": 19,
                    "column": 10,
                    "byte_offset": 499
                },
                "end": {
                    "file": "seating-chart.twig",
                    "line": 19,
                    "column": 20,
                    "byte_offset": 509
                }
            },
            "visibility": "unknown"
        }
    ]
}

symbols reports five entries: seating_chart as kind class (the block suffix isn't in the symbol-kind vocabulary), section_count as variable, the length filter call as function, section as variable (the loop-variable suffix maps there), and seat_label as function; the {% extends %} and {% if %} tags are absent, since neither has a rule in symbols.scm.

Query

18 query tools, the same on every supported language. Descriptions live in the shared reference: /docs/query-tools.

callers control_flow data_flow definition diagnostics effect_closure effect_summary fix_auto get_type graph import_organize interface mutations references repo_outline skeleton symbols symbols_batch

← TSXTypeScript →