Query language for tree-sitter ASTs with type inference.
# Explore a source file's tree-sitter AST
plotnik ast app.ts
# Validate a query against a grammar
plotnik check -q 'Func = (function_declaration) @fn' -l typescript
# Generate TypeScript types
plotnik infer -q 'Func = (function_declaration) @fn' -l typescript
# List supported languages
plotnik lang list
# Dump grammar for a language
plotnik lang dump typescript| Command | Input | Purpose | -l flag |
|---|---|---|---|
run |
both | Run query, output JSON | Shebang or extension |
check |
query | Validate query | Optional (enables grammar validation) |
ast |
both | Show AST of query and/or source | Shebang or extension |
infer |
query | Generate type definitions | Required |
dump |
query | Show bytecode | Optional (enables linking) |
trace |
both | Trace query execution | Shebang or extension |
lang list |
— | List supported languages | — |
lang dump |
— | Dump grammar for a language | — |
completions |
— | Generate shell completions | — |
exec is kept as a hidden alias for run.
Bare invocation: when the first argument is a .ptk file, the run
subcommand is implied — plotnik query.ptk app.js works. Combined with a
shebang line, query files become directly executable (see
Shebang).
Show AST of query and/or source file. Use this to discover node kinds and structure.
# Show tree-sitter AST of source file
plotnik ast app.ts
# Show query AST
plotnik ast query.ptk
# Show both query and source AST
plotnik ast query.ptk app.ts
# Include anonymous nodes (literals, punctuation)
plotnik ast app.ts --rawFlags:
| Flag | Purpose |
|---|---|
--raw |
Include anonymous nodes (literals, punctuation) |
Show compiled bytecode. For debugging the compiler.
# Unlinked bytecode (parse + analyze + emit)
plotnik dump -q 'Q = (identifier) @id'
# Linked bytecode (+ link against grammar)
plotnik dump -q 'Q = (identifier) @id' -l typescriptWithout -l: node kinds are unresolved symbols.
With -l: node kinds are resolved to grammar IDs.
Validate a query. Like cargo check.
# Validate syntax, types, recursion (no grammar)
plotnik check -q 'Q = (identifier) @id'
# Also validate node kinds and fields against grammar
plotnik check -q 'Q = (function_declaration) @fn' -l typescriptWithout -l: validates syntax, type inference, recursion rules, alt consistency.
With -l: also validates node kinds and field names exist in grammar.
Flags:
| Flag | Purpose |
|---|---|
-l, --lang |
Enable grammar validation |
--strict |
Treat warnings as errors |
--json |
Output diagnostics as JSON |
On success: silent, exits 0. On error: prints diagnostics to stderr, exits 1.
With --json, on exit 0 or 1 stdout is a JSON array of diagnostics ([]
when the query is clean), each with code, severity, message, span
(file/line/column/offset), and optional related, fix, and hints.
Exit 2 means the question couldn't be answered — the error goes to stderr
as text and no JSON is emitted:
plotnik check query.ptk --json | jq '.[].code'Generate type definitions from a query. Currently supports TypeScript.
# Generate TypeScript types
plotnik infer -q 'Func = (function_declaration) @fn' -l javascript
# Write to file
plotnik infer -q 'Func = (function_declaration) @fn' -l javascript -o types.d.ts
# Verbose node shape (includes line/column)
plotnik infer -q 'Func = (function_declaration) @fn' -l javascript --verbose-nodes
# Skip boilerplate (Node/Point types, exports)
plotnik infer -q 'Q = (identifier) @id' -l js --no-node-type --no-exportFlags:
| Flag | Purpose |
|---|---|
-l, --lang LANG |
Target language grammar (required) |
-o, --output FILE |
Write output to file |
--format FORMAT |
Output format (typescript, ts) |
--verbose-nodes |
Include line/column in Node type |
--no-node-type |
Don't emit Node/Point definitions |
--no-export |
Don't add export keyword |
--void-type TYPE |
Type for void results (undefined or null) |
Language information and grammar tools.
List all supported tree-sitter languages with their aliases.
plotnik lang listbash (sh, shell)
c
cpp (c++, cxx, cc)
javascript (js, jsx, ecmascript, es)
typescript (ts)
...
Dump a language's grammar in Plotnik-like syntax. Useful for learning how to write queries against a grammar.
plotnik lang dump json
plotnik lang dump typescriptThe output uses a syntax similar to Plotnik queries:
(node_kind)— named node (queryable)"literal"— anonymous node (queryable)(_hidden ...)— hidden rule (not queryable, children inline){...}— sequence (ordered children)[...]— alternation (first match)? * +— quantifiers"x"!— immediate token (no whitespace before)field: ...— named fieldT :: supertype— supertype declaration
Execute a query against source code and output JSON matches.
# Two positional arguments: QUERY SOURCE
plotnik run query.ptk app.js
# Bare invocation (run is implied for .ptk files)
plotnik query.ptk app.js
# Inline query + positional source (most common)
plotnik run -q 'Q = (identifier) @id' app.js
# All inline (requires -l)
plotnik run -q 'Q = (identifier) @id' -s 'let x = 1' -l javascript
# Start from a specific definition
plotnik run query.ptk app.js --entry FunctionDefFlags:
| Flag | Purpose |
|---|---|
-q, --query |
Inline query text |
-s, --source |
Inline source text |
-l, --lang |
Language (inferred from file ext) |
--compact |
Output compact JSON |
--entry NAME |
Start from specific definition |
Trace query execution for debugging.
# Inline query + positional source
plotnik trace -q 'Q = (identifier) @id' app.js
# Two positional arguments
plotnik trace query.ptk app.js
# All inline
plotnik trace -q 'Q = (identifier) @id' -s 'let x = 1' -l js
# Skip result, show only effects
plotnik trace query.ptk app.js --no-result
# Increase verbosity
plotnik trace query.ptk app.js -v # verbose
plotnik trace query.ptk app.js -vv # very verboseFlags:
| Flag | Purpose |
|---|---|
-v |
Verbose output |
-vv |
Very verbose output |
--no-result |
Skip materialization |
--fuel N |
Execution fuel limit |
--entry |
Start from specific definition |
These commands take a single input. Use either:
- Positional:
plotnik dump query.ptk - Flag:
plotnik dump -q 'Q = ...'
These commands can take query, source, or both inputs. Use any combination:
| Pattern | Query from | Source from |
|---|---|---|
run QUERY SOURCE |
1st positional | 2nd positional |
run -q '...' SOURCE |
-q flag |
positional |
run -s '...' QUERY -l lang |
positional | -s flag |
run -q '...' -s '...' -l lang |
-q flag |
-s flag |
Key rule: When -q is provided with one positional, it becomes SOURCE.
Priority: explicit -l (must agree with the shebang) > shebang declaration >
source file extension.
| Input type | Language |
|---|---|
.ptk w/ shebang |
Declared in shebang |
| Source file | Inferred from .ext |
Inline (-s) |
Requires -l (or shebang) |
Line 1 of a .ptk file may declare its language (and optionally an
entrypoint) via a shebang:
#!/usr/bin/env -S plotnik run -l typescript
Func = (function_declaration name: (identifier) @name)
All commands (run, check, infer, ast, trace, dump) read the
declaration; presentation flags in the shebang are ignored unless executing.
An explicit -l must agree with the declaration, otherwise the command errors.
With chmod +x, the file becomes directly executable:
./functions.ptk app.tsIn a workspace directory, all shebangs must agree on the language.
Use - as the file argument:
# Query from stdin
echo 'Q = (identifier) @id' | plotnik dump -
# Source from stdin
cat app.ts | plotnik ast -
# Run: query from stdin, source from file
echo 'Q = (identifier) @id' | plotnik run - app.js-
Explore the source AST to understand node structure:
plotnik ast example.ts
-
Write a query and validate against the grammar:
plotnik check -q 'Func = (function_declaration name: (identifier) @name)' -l typescript -
Generate TypeScript types:
plotnik infer -q 'Func = (function_declaration name: (identifier) @name)' \ -l typescript -o func.d.ts
For complex queries, use files with .ptk extension:
; queries/functions.ptk
; Match function declarations with their parameters
Func = (function_declaration
name: (identifier) @name
parameters: (formal_parameters
{(required_parameter
pattern: (identifier) @param_name
type: (_) @param_type
) @param}* @params
)
)
plotnik infer queries/functions.ptk -l typescript -o types.d.tsColor is auto-detected based on terminal capability.
| Option | Behavior |
|---|---|
--color auto |
Detect TTY (default) |
--color always |
Force colors |
--color never |
Disable colors |
Respects the NO_COLOR, CLICOLOR_FORCE, and TERM=dumb conventions.
Plotnik provides detailed diagnostics with source context:
error: unknown node type 'function_decl'
--> query.ptk:3:5
|
3 | (function_decl name: (identifier) @name)
| ^^^^^^^^^^^^^ not a valid TypeScript node type
|
help: did you mean 'function_declaration'?
Common errors:
| Error | Cause | Fix |
|---|---|---|
unknown node type |
Typo in node kind | Check plotnik ast file for valid types |
missing closing ) |
Unclosed tree pattern | Match parentheses |
expected expression |
Invalid syntax | Check query syntax |
strict dimensionality violation |
Quantified captures need row wrapper | Use {...}* @rows pattern |
Uniform across all commands:
| Code | Meaning |
|---|---|
| 0 | Yes/success (match found, query valid) |
| 1 | Domain "no" (run: no match; check: invalid) |
| 2 | Couldn't answer (usage, IO, or internal error) |
- Start with
astto explore unfamiliar codebases - Use
--rawto see all tokens including literals - Run
checkbeforeinferto catch grammar errors early - Use
dumpto debug query parsing or bytecode - Use query files for anything beyond one-liners
- Declare the language in a shebang so
-lis never needed for that file