pi-tree-sitter
Pre-write syntax validation for pi using tree-sitter WASM grammars
Package details
Install pi-tree-sitter from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-tree-sitter- Package
pi-tree-sitter- Version
0.2.8- Published
- Aug 3, 2026
- Downloads
- 1,694/mo · 360/wk
- Author
- markokocic
- License
- EPL-2.0
- Types
- extension
- Size
- 156.5 KB
- Dependencies
- 1 dependency · 3 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-tree-sitter
Pre-write syntax validation and structural code tools for pi using tree-sitter WASM grammars.
Write-time validation: hooks into write and edit tools to parse content before it hits disk. If tree-sitter finds syntax errors, the extension blocks the tool with actionable feedback — line, column, source snippet, and for MISSING nodes, what token was expected. The LLM sees the error in the same turn and self-corrects.
Semantic code tools: registers list_symbols, find_definition, find_callers, find_callees, and get_symbol_body tools so the agent can query code structure — functions, classes, methods, interfaces — without grepping or reading whole files.
Inspired by dirge's syntax_validator.rs and semantic adapters.
Installation
pi install npm:pi-tree-sitter
Git version
pi install git:github.com/markokocic/pi-tree-sitter
Or clone and use locally:
git clone https://github.com/markokocic/pi-tree-sitter.git
cd pi-tree-sitter
npm install
pi install .
Run ad-hoc without installing:
pi -e ./path/to/pi-tree-sitter
Tools
| Tool | Parameters | Description |
|---|---|---|
list_symbols |
path?, kind? |
List symbols (functions, classes, methods, etc.) in a file or across the project. Parses code with tree-sitter for accurate results. Use this instead of grep when looking for code structure. |
find_definition |
name |
Find where a SYMBOL (function, class, type, etc.) is DEFINED across the project. Uses tree-sitter for precise structural matching. NOT for finding files by name — use find_files for that. NOT for content search — use grep. |
find_callers |
name, path? |
Find all call sites of a function or method across the project, with file path and line number. Excludes the definition site. |
find_callees |
path, name |
Find all functions/methods called by a given symbol, with line number per call site. |
get_symbol_body |
path, name |
Get the full source code of a named symbol (function, class, method, etc.) from a file. Uses tree-sitter to precisely extract by byte range. |
All tools parse code with tree-sitter on demand — no caching, always fresh.
TUI Rendering
All symbol tools include custom renderCall and renderResult for a polished terminal experience:
- Tool title shows the tool name and its parameters inline:
find_definition — myFunctionlist_symbols src/file.ts [kind: function] - Collapsed (default — press
Ctrl+Oto expand): compact summary:✓ 42 symbols across 5 files✓ 3 definitions for 'myFunction' - Expanded (
Ctrl+O): full detail output get_symbol_bodyrenders expanded source with syntax highlighting viahighlightCode(), auto-detecting the language from the file extension
Write-time validation
The extension hooks write and edit tools. Before content hits disk, it's parsed with the matching tree-sitter grammar. If ERROR or MISSING nodes are found (capped at 10), the tool is blocked with:
Syntax check failed for src/main.rs: 2 error(s) detected by tree-sitter.
Fix and re-submit. (This is a pre-write guard — the file was NOT modified.)
missing `}` at 42:1: fn main() {
syntax error at 15:8: let x =
For edit tools, the extension runs the edit tool's own execution in memory (file operations redirected) and validates the result — so the guard always checks exactly what the tool would write. If an oldText matched only a prefix of a line — leaving trailing characters behind after the replacement, a common cause of rejected edits — the block message names that edit and line instead of only showing the resulting syntax error. Edits the edit tool itself would reject with a precise error (text not found, non-unique, overlapping) are left for the tool to report. For languages without WASM grammars, a comment/string-aware delimiter-balance scanner provides fallback validation.
Languages
WASM grammars + symbol tools (21 configs)
| Language | Extensions | Symbols |
|---|---|---|
| TypeScript / JavaScript | .ts, .tsx, .mts, .cts, .js, .jsx, .mjs, .cjs |
functions, classes, interfaces, types, methods, variables |
| Python | .py, .pyi |
functions, classes, methods, decorated definitions |
| Rust | .rs |
functions, structs, enums, traits, impl methods |
| Go | .go |
functions, methods, structs, interfaces |
| Java | .java |
classes, interfaces, enums |
| C# | .cs |
classes, structs, interfaces, enums, methods, namespaces |
| Kotlin | .kt, .kts |
functions, classes, interfaces, objects, properties |
| Ruby | .rb |
methods, classes, modules |
| PHP | .php |
functions, classes, interfaces, traits, methods |
| Dart | .dart |
functions, classes, mixins, enums, methods, variables |
| C | .c, .h |
functions, structs, unions, enums |
| C++ | .cpp, .cc, .cxx, .hpp, .hh, .hxx |
functions, classes, structs, namespaces |
| Bash | .sh, .bash |
functions |
| Clojure / EDN / Babashka / ClojureDart | .clj, .cljs, .cljc, .cljd, .edn, .bb |
functions, vars, protocols, records |
| Elixir | .ex, .exs |
functions, modules, protocols |
| Scala | .scala |
functions, classes, traits, objects |
| Swift | .swift |
functions, classes, structs, protocols, enums |
| Lua | .lua |
functions |
| Zig | .zig |
functions, variables, containers |
| Scheme | .scm, .ss |
validation only |
| Racket | .rkt |
validation only |
WASM validation only (no symbol tools)
| Language | Extensions |
|---|---|
| Haskell | .hs, .lhs |
| CSS | .css |
| HTML | .htm, .html |
| JSON | .json |
| TOML | .toml |
| YAML | .yaml, .yml |
| Vue | .vue |
Delimiter balance only (no WASM grammar available)
| Language | Extensions |
|---|---|
| Common Lisp | .lisp, .lsp, .cl |
| Emacs Lisp | .el |
| Fennel | .fnl |
| Janet | .janet, .jdn |
Grammar caching
WASM grammars are fetched from jsDelivr CDN and cached to ~/.cache/pi-tree-sitter/.
Each grammar has three files:
<wasm>— the WASM binary<wasm>.etag— server ETag for conditional requests<wasm>.date— last-checked timestamp
On every load, the .date file is checked. Only if 30+ days old does the extension
revalidate against the CDN using If-None-Match with the stored ETag:
- 304 Not Modified → touches
.date(zero bytes transferred, timer reset) - 200 OK → downloads updated grammar, saves new WASM + ETag + date
- Network error → keeps cache, touches
.date(retries in 30 days)
On first download, the bytes are verified with Language.load() before persisting.
If cached bytes are ever corrupted, they are deleted and re-downloaded on the next access.
How it works
- Write-time validation hooks
tool_callevents forwriteandedit - Semantic tools are registered via
pi.registerTool()with TypeBox parameter schemas - Each tool parses the relevant file(s) with tree-sitter on demand (no in-memory cache)
- Per-language extractors map grammar-specific node types to a unified
Symbolkind - Callee queries use tree-sitter S-expression queries for each language
Project structure
pi-tree-sitter/
index.ts # Extension entry: write/edit hooks + 5 tool registrations
src/
grammar.ts # LANGUAGE_MAP, WASM loading from CDN, disk cache with ETag
delimiter.ts # Comment/string-aware delimiter balance scanner (fallback)
edit-guard.ts # In-memory edit simulation via the tool's own execute + prefix-match diagnosis
languages.ts # 21 per-language configs: extractors + callee queries
files.ts # Recursive project file discovery
License
EPL-2.0 — Copyright 2026 Marko Kocic