PRQL — 18 Operations for AI Agents
PRQL rethinks SQL as a pipeline: transforms that read top to bottom the way data actually flows. act101 reads those pipelines structurally, so agents follow each transform step without mentally unwinding nested queries.
This page is the canonical reference an AI coding agent uses to refactor, query, and analyze PRQL 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 PRQL examples
act101 reads a PRQL file's let-bound pipelines, let-bound function definitions, and every from clause's table reference as declarations. The skeleton tags all three the same way, function, regardless of whether the declaration is a reusable pipeline like route_summary, a scalar function like pct_of, or simply the table named after from — including a from nested inside a let pipeline's own body. symbols narrows the same file to just the let bindings — reporting a pipeline binding's real kind, variable, and a function definition's real kind, function — and drops every from clause the skeleton listed, since symbols.scm has no rule for from. The unit of structure in this grammar is the top-level statement: neither query descends into a pipeline's own transforms (filter, group, aggregate) or a function's parameters. 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 ridership and on-time pipelines, helper function, and table references as a skeleton
ferry-ridership.prql binds route_summary and on_time_summary to two pipelines that both filter the ridership table to the harbor-express route — one aggregating rider totals per route, the other on-time trip counts — defines a pct_of helper function between them, then queries route_summary for the final result.
$ act query skeleton ferry-ridership.prql
Before
let route_summary = (
from ridership
filter route == "harbor-express"
group route (
aggregate {
total_riders = sum passengers,
trip_count = count this
}
)
)
let pct_of total value -> value / total * 100
let on_time_summary = (
from ridership
filter route == "harbor-express"
group route (
aggregate {
on_time_trips = sum (delay_minutes <= 5),
trip_count = count this
}
)
)
from route_summary
select {route, total_riders, trip_count}
Output
{
"type": "Skeleton",
"declarations": [
{
"kind": "function",
"name": "route_summary",
"range": {
"start": {
"file": "ferry-ridership.prql",
"line": 1,
"column": 1,
"byte_offset": 0
},
"end": {
"file": "ferry-ridership.prql",
"line": 10,
"column": 2,
"byte_offset": 184
}
},
"name_range": {
"start": {
"file": "ferry-ridership.prql",
"line": 1,
"column": 5,
"byte_offset": 4
},
"end": {
"file": "ferry-ridership.prql",
"line": 1,
"column": 18,
"byte_offset": 17
}
}
},
{
"kind": "function",
"name": "ridership",
"range": {
"start": {
"file": "ferry-ridership.prql",
"line": 2,
"column": 3,
"byte_offset": 24
},
"end": {
"file": "ferry-ridership.prql",
"line": 2,
"column": 17,
"byte_offset": 38
}
},
"name_range": {
"start": {
"file": "ferry-ridership.prql",
"line": 2,
"column": 8,
"byte_offset": 29
},
"end": {
"file": "ferry-ridership.prql",
"line": 2,
"column": 17,
"byte_offset": 38
}
}
},
{
"kind": "function",
"name": "pct_of",
"range": {
"start": {
"file": "ferry-ridership.prql",
"line": 12,
"column": 1,
"byte_offset": 186
},
"end": {
"file": "ferry-ridership.prql",
"line": 12,
"column": 46,
"byte_offset": 231
}
},
"name_range": {
"start": {
"file": "ferry-ridership.prql",
"line": 12,
"column": 5,
"byte_offset": 190
},
"end": {
"file": "ferry-ridership.prql",
"line": 12,
"column": 11,
"byte_offset": 196
}
}
},
{
"kind": "function",
"name": "on_time_summary",
"range": {
"start": {
"file": "ferry-ridership.prql",
"line": 14,
"column": 1,
"byte_offset": 233
},
"end": {
"file": "ferry-ridership.prql",
"line": 23,
"column": 2,
"byte_offset": 430
}
},
"name_range": {
"start": {
"file": "ferry-ridership.prql",
"line": 14,
"column": 5,
"byte_offset": 237
},
"end": {
"file": "ferry-ridership.prql",
"line": 14,
"column": 20,
"byte_offset": 252
}
}
},
{
"kind": "function",
"name": "ridership",
"range": {
"start": {
"file": "ferry-ridership.prql",
"line": 15,
"column": 3,
"byte_offset": 259
},
"end": {
"file": "ferry-ridership.prql",
"line": 15,
"column": 17,
"byte_offset": 273
}
},
"name_range": {
"start": {
"file": "ferry-ridership.prql",
"line": 15,
"column": 8,
"byte_offset": 264
},
"end": {
"file": "ferry-ridership.prql",
"line": 15,
"column": 17,
"byte_offset": 273
}
}
},
{
"kind": "function",
"name": "route_summary",
"range": {
"start": {
"file": "ferry-ridership.prql",
"line": 25,
"column": 1,
"byte_offset": 432
},
"end": {
"file": "ferry-ridership.prql",
"line": 25,
"column": 19,
"byte_offset": 450
}
},
"name_range": {
"start": {
"file": "ferry-ridership.prql",
"line": 25,
"column": 6,
"byte_offset": 437
},
"end": {
"file": "ferry-ridership.prql",
"line": 25,
"column": 19,
"byte_offset": 450
}
}
}
]
}
The skeleton reports six function declarations: route_summary and on_time_summary for the two let-bound pipelines, ridership for each pipeline's own from clause, pct_of for the function definition, and route_summary again for the file's final top-level from.
List the let-bound pipelines and function as symbols
The file binds exactly three things with let — two pipelines and one function; the two from clauses inside them and the file's final from reference tables rather than binding anything.
$ act query symbols ferry-ridership.prql
Before
let route_summary = (
from ridership
filter route == "harbor-express"
group route (
aggregate {
total_riders = sum passengers,
trip_count = count this
}
)
)
let pct_of total value -> value / total * 100
let on_time_summary = (
from ridership
filter route == "harbor-express"
group route (
aggregate {
on_time_trips = sum (delay_minutes <= 5),
trip_count = count this
}
)
)
from route_summary
select {route, total_riders, trip_count}
Output
{
"type": "Symbols",
"symbols": [
{
"name": "route_summary",
"kind": "variable",
"range": {
"start": {
"file": "ferry-ridership.prql",
"line": 1,
"column": 5,
"byte_offset": 4
},
"end": {
"file": "ferry-ridership.prql",
"line": 1,
"column": 18,
"byte_offset": 17
}
},
"visibility": "unknown"
},
{
"name": "pct_of",
"kind": "function",
"range": {
"start": {
"file": "ferry-ridership.prql",
"line": 12,
"column": 5,
"byte_offset": 190
},
"end": {
"file": "ferry-ridership.prql",
"line": 12,
"column": 11,
"byte_offset": 196
}
},
"visibility": "unknown"
},
{
"name": "on_time_summary",
"kind": "variable",
"range": {
"start": {
"file": "ferry-ridership.prql",
"line": 14,
"column": 5,
"byte_offset": 237
},
"end": {
"file": "ferry-ridership.prql",
"line": 14,
"column": 20,
"byte_offset": 252
}
},
"visibility": "unknown"
}
]
}
symbols reports exactly three entries — route_summary and on_time_summary as variable and pct_of as function — dropping every from clause that skeleton listed.
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