Angular — 18 Operations for AI Agents
Angular templates are where component logic meets the DOM: bindings, directives, structural control flow, event handlers. act101 gives agents the template as a structural map, so they find the one binding that matters without parsing HTML by eye.
This page is the canonical reference an AI coding agent uses to refactor, query, and analyze Angular 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.
Worked Angular examples
act101 reads an Angular template's HTML elements — start tags and self-closing tags — as element declarations named for the tag, and reads its four control-flow blocks — @if, @for, @switch, @defer — as block declarations named for the keyword itself. symbols covers the same elements (plus any id attribute value) as definition entries, but reports every one under a flat class kind, since the query captures a bare @definition with no kind suffix; the control-flow blocks don't reach symbols at all. The unit of structure in this grammar is the individual HTML element: a template that nests a loop inside a conditional reports every element at every nesting level, not just the outermost wrapper. 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 template's elements and control-flow blocks
exhibit-wing.ng is a museum gallery-wing template: an @if block hides the exhibit list when a wing is under conservation, and its @else branch holds a @for block over wing.exhibits with an @empty fallback.
$ act query skeleton exhibit-wing.ng
Before
<section class="gallery-wing" *ngIf="wing.open">
<h1>{{ wing.name }}</h1>
@if (wing.underConservation) {
<p class="notice">Temporarily closed for conservation</p>
} @else {
<ul class="exhibit-list">
@for (item of wing.exhibits; track item.id) {
<li [class.onLoan]="item.onLoan">
<h3>{{ item.title }}</h3>
<span class="era">{{ item.era }}</span>
</li>
} @empty {
<li>No exhibits currently on display</li>
}
</ul>
}
<button (click)="requestCatalog(wing.id)">Request catalog</button>
</section>
Output
{
"type": "Skeleton",
"declarations": [
{
"kind": "element",
"name": "section",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 1,
"column": 1,
"byte_offset": 0
},
"end": {
"file": "exhibit-wing.ng",
"line": 18,
"column": 11,
"byte_offset": 575
}
},
"name_range": {
"start": {
"file": "exhibit-wing.ng",
"line": 1,
"column": 2,
"byte_offset": 1
},
"end": {
"file": "exhibit-wing.ng",
"line": 1,
"column": 9,
"byte_offset": 8
}
}
},
{
"kind": "element",
"name": "h1",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 2,
"column": 3,
"byte_offset": 51
},
"end": {
"file": "exhibit-wing.ng",
"line": 2,
"column": 27,
"byte_offset": 75
}
},
"name_range": {
"start": {
"file": "exhibit-wing.ng",
"line": 2,
"column": 4,
"byte_offset": 52
},
"end": {
"file": "exhibit-wing.ng",
"line": 2,
"column": 6,
"byte_offset": 54
}
}
},
{
"kind": "block",
"name": "if",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 3,
"column": 3,
"byte_offset": 78
},
"end": {
"file": "exhibit-wing.ng",
"line": 5,
"column": 4,
"byte_offset": 174
}
},
"name_range": {
"start": {
"file": "exhibit-wing.ng",
"line": 3,
"column": 4,
"byte_offset": 79
},
"end": {
"file": "exhibit-wing.ng",
"line": 3,
"column": 6,
"byte_offset": 81
}
}
},
{
"kind": "element",
"name": "p",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 4,
"column": 5,
"byte_offset": 113
},
"end": {
"file": "exhibit-wing.ng",
"line": 4,
"column": 62,
"byte_offset": 170
}
},
"name_range": {
"start": {
"file": "exhibit-wing.ng",
"line": 4,
"column": 6,
"byte_offset": 114
},
"end": {
"file": "exhibit-wing.ng",
"line": 4,
"column": 7,
"byte_offset": 115
}
}
},
{
"kind": "element",
"name": "ul",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 6,
"column": 5,
"byte_offset": 187
},
"end": {
"file": "exhibit-wing.ng",
"line": 15,
"column": 10,
"byte_offset": 491
}
},
"name_range": {
"start": {
"file": "exhibit-wing.ng",
"line": 6,
"column": 6,
"byte_offset": 188
},
"end": {
"file": "exhibit-wing.ng",
"line": 6,
"column": 8,
"byte_offset": 190
}
}
},
{
"kind": "block",
"name": "for",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 7,
"column": 7,
"byte_offset": 219
},
"end": {
"file": "exhibit-wing.ng",
"line": 12,
"column": 8,
"byte_offset": 414
}
},
"name_range": {
"start": {
"file": "exhibit-wing.ng",
"line": 7,
"column": 8,
"byte_offset": 220
},
"end": {
"file": "exhibit-wing.ng",
"line": 7,
"column": 11,
"byte_offset": 223
}
}
},
{
"kind": "element",
"name": "li",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 8,
"column": 9,
"byte_offset": 273
},
"end": {
"file": "exhibit-wing.ng",
"line": 11,
"column": 14,
"byte_offset": 406
}
},
"name_range": {
"start": {
"file": "exhibit-wing.ng",
"line": 8,
"column": 10,
"byte_offset": 274
},
"end": {
"file": "exhibit-wing.ng",
"line": 8,
"column": 12,
"byte_offset": 276
}
}
},
{
"kind": "element",
"name": "h3",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 9,
"column": 11,
"byte_offset": 317
},
"end": {
"file": "exhibit-wing.ng",
"line": 9,
"column": 36,
"byte_offset": 342
}
},
"name_range": {
"start": {
"file": "exhibit-wing.ng",
"line": 9,
"column": 12,
"byte_offset": 318
},
"end": {
"file": "exhibit-wing.ng",
"line": 9,
"column": 14,
"byte_offset": 320
}
}
},
{
"kind": "element",
"name": "span",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 10,
"column": 11,
"byte_offset": 353
},
"end": {
"file": "exhibit-wing.ng",
"line": 10,
"column": 50,
"byte_offset": 392
}
},
"name_range": {
"start": {
"file": "exhibit-wing.ng",
"line": 10,
"column": 12,
"byte_offset": 354
},
"end": {
"file": "exhibit-wing.ng",
"line": 10,
"column": 16,
"byte_offset": 358
}
}
},
{
"kind": "element",
"name": "li",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 13,
"column": 9,
"byte_offset": 432
},
"end": {
"file": "exhibit-wing.ng",
"line": 13,
"column": 50,
"byte_offset": 473
}
},
"name_range": {
"start": {
"file": "exhibit-wing.ng",
"line": 13,
"column": 10,
"byte_offset": 433
},
"end": {
"file": "exhibit-wing.ng",
"line": 13,
"column": 12,
"byte_offset": 435
}
}
},
{
"kind": "element",
"name": "button",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 17,
"column": 3,
"byte_offset": 498
},
"end": {
"file": "exhibit-wing.ng",
"line": 17,
"column": 69,
"byte_offset": 564
}
},
"name_range": {
"start": {
"file": "exhibit-wing.ng",
"line": 17,
"column": 4,
"byte_offset": 499
},
"end": {
"file": "exhibit-wing.ng",
"line": 17,
"column": 10,
"byte_offset": 505
}
}
}
]
}
The skeleton reports nine element declarations, from section down to button, including both li elements, alongside two block declarations, if and for, one for each control-flow keyword the fixture uses; the @else and @empty branches don't get their own entries.
List every element as a flat symbol
Inside the for block, each li renders an h3 for item.title and a span for item.era.
$ act query symbols exhibit-wing.ng
Before
<section class="gallery-wing" *ngIf="wing.open">
<h1>{{ wing.name }}</h1>
@if (wing.underConservation) {
<p class="notice">Temporarily closed for conservation</p>
} @else {
<ul class="exhibit-list">
@for (item of wing.exhibits; track item.id) {
<li [class.onLoan]="item.onLoan">
<h3>{{ item.title }}</h3>
<span class="era">{{ item.era }}</span>
</li>
} @empty {
<li>No exhibits currently on display</li>
}
</ul>
}
<button (click)="requestCatalog(wing.id)">Request catalog</button>
</section>
Output
{
"type": "Symbols",
"symbols": [
{
"name": "section",
"kind": "class",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 1,
"column": 2,
"byte_offset": 1
},
"end": {
"file": "exhibit-wing.ng",
"line": 1,
"column": 9,
"byte_offset": 8
}
},
"visibility": "unknown"
},
{
"name": "h1",
"kind": "class",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 2,
"column": 4,
"byte_offset": 52
},
"end": {
"file": "exhibit-wing.ng",
"line": 2,
"column": 6,
"byte_offset": 54
}
},
"visibility": "unknown"
},
{
"name": "p",
"kind": "class",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 4,
"column": 6,
"byte_offset": 114
},
"end": {
"file": "exhibit-wing.ng",
"line": 4,
"column": 7,
"byte_offset": 115
}
},
"visibility": "unknown"
},
{
"name": "ul",
"kind": "class",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 6,
"column": 6,
"byte_offset": 188
},
"end": {
"file": "exhibit-wing.ng",
"line": 6,
"column": 8,
"byte_offset": 190
}
},
"visibility": "unknown"
},
{
"name": "li",
"kind": "class",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 8,
"column": 10,
"byte_offset": 274
},
"end": {
"file": "exhibit-wing.ng",
"line": 8,
"column": 12,
"byte_offset": 276
}
},
"visibility": "unknown"
},
{
"name": "h3",
"kind": "class",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 9,
"column": 12,
"byte_offset": 318
},
"end": {
"file": "exhibit-wing.ng",
"line": 9,
"column": 14,
"byte_offset": 320
}
},
"visibility": "unknown"
},
{
"name": "span",
"kind": "class",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 10,
"column": 12,
"byte_offset": 354
},
"end": {
"file": "exhibit-wing.ng",
"line": 10,
"column": 16,
"byte_offset": 358
}
},
"visibility": "unknown"
},
{
"name": "li",
"kind": "class",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 13,
"column": 10,
"byte_offset": 433
},
"end": {
"file": "exhibit-wing.ng",
"line": 13,
"column": 12,
"byte_offset": 435
}
},
"visibility": "unknown"
},
{
"name": "button",
"kind": "class",
"range": {
"start": {
"file": "exhibit-wing.ng",
"line": 17,
"column": 4,
"byte_offset": 499
},
"end": {
"file": "exhibit-wing.ng",
"line": 17,
"column": 10,
"byte_offset": 505
}
},
"visibility": "unknown"
}
]
}
symbols reports the same nine elements as definition entries, but every one comes back kind class instead of element; the if and for blocks that appeared in the skeleton are absent, since symbols.scm has no rule for them.
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