pi-io-tools
Anchor-based file I/O tools and deterministic shell-output reduction for the Pi coding agent.
Package details
Install pi-io-tools from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-io-tools- Package
pi-io-tools- Version
0.1.2- Published
- Jul 25, 2026
- Downloads
- 442/mo · 442/wk
- Author
- daoguademeng
- License
- MIT
- Types
- extension
- Size
- 7 MB
- Dependencies
- 10 dependencies · 4 peers
Pi manifest JSON
{
"extensions": [
"./extension-composition/pi-extension.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-io-tools
a tool set your agent would love to use
Agent-first file tools and deterministic shell-output reduction for the Pi coding agent.
Three black-box agent trials consistently highlighted the cross-tool workflow. read, write, grep, and search return edit-ready LINE:HASH|content anchors; edit consumes the same anchors; refs establishes binding truth; and rename proves a complete change before it writes. The shared result language reduces translation between one tool call and the next.
The design priority is fidelity first, lower agent friction second, and token savings third. Degradation and incomplete evidence are reported rather than hidden behind a fallback.
Install
pi install npm:pi-io-tools
Update or remove the package with:
pi update npm:pi-io-tools
pi remove npm:pi-io-tools
You can also install the public repository directly:
pi install git:github.com/daoguademeng/pi-io-tools-extension
Requirements:
- Node.js 22.19.0 or newer
- A current Pi installation
- ripgrep for
grep - Git for repository-aware file-set selection and Git-based installation
The extension is enabled with zero configuration.
File tools
The intended loop is simple:
grep/search → read(symbol + local bundle) → refs → edit/write/rename → bash
Each stage returns data the next stage can use directly. Omitted output is counted, degradation is named, and recovery calls are explicit.
read — progressive and structural reading
read is progressive by default. A Structure Map lists declarations before loading source, symbol selects an exact declaration such as Class.method or top-level.helper, and a Local Symbol Bundle appends binding-proven same-file dependencies. Ambiguous symbols return qualified candidates; bundle support is labelled complete, degraded, or incomplete.
The same interface provides Markdown outlines and structure maps for JSON/JSONC, YAML, and TOML. Images remain native Pi attachments; binary text is rejected.
write — anchored and context-efficient writes
write creates or replaces a complete text file, creates missing parent directories, does not run a formatter, and immediately returns edit-ready anchors. The result can flow directly into edit without a verification read.
A conventional write turn carries the new file twice into the next model request: once as raw content in the assistant's tool call and again as the anchored result. fileTools.write.callRecordInContext controls that duplicate cost:
| Mode | Model-context shape |
|---|---|
elide (default) |
Removes each successful write call record and its raw content from the request-local model context. The authoritative anchored result is preserved as a clearly marked user-role transport message after the turn's contiguous tool-result run. |
full |
Preserves Pi's conventional assistant tool call and tool result, including the complete raw content argument. |
An elided result looks like this:
[`write` call record elided; result is authoritative — no verification read needed]
Created path/to/file.ts (1234 bytes)
1:a1b|import ...
2:c2d|...
The user role here is transport, not a new human interruption. Elision changes only Pi's request-local context copy, never the file, persisted session history, or displayed transcript. Failed or ambiguous write/result pairings remain untouched, and parallel elided results preserve original call order.
Both modes use the same anchored-result projection gate. By default, the full result is shown when it fits both 1,000 lines and 32 KiB, or when the configured head and tail already cover the whole file. Otherwise it keeps the first 50 and last 10 lines with an exact omitted range and follow-up read hint.
To restore the conventional context shape:
{
"fileTools": {
"write": {
"callRecordInContext": "full"
}
}
}
edit — atomic anchored edits
edit validates every operation against one pre-edit snapshot, rejects overlaps and ambiguities, then commits the batch once. Earlier operations do not require recalculating later anchors, and one invalid operation prevents a partial write.
When a line moved but its hash is globally unique, edit relocates the stale anchor and reports it. Multiple candidates block the edit and include their context. Successful edits return fresh change-region anchors; parser-proven syntax regressions are reported without blocking deliberate intermediate edits.
grep — anchored text search
grep turns ripgrep matches into anchored results with stable ordering and merged context. It can summarize counts per file, search multiline text, or group matches by their smallest enclosing symbol.
When a result budget is reached, grep reports the omitted files, matches, and lines plus a concrete rerun limit. Anchored matches and context can be passed directly to edit.
search — structural search
search uses AST shapes: $_ matches one node and $$$ matches zero or more. Results include source spans, enclosing symbols, and anchors. Parentheses are literal syntax nodes rather than regex grouping; pattern feedback explains parse errors and common shape mismatches.
Git-aware file-set controls select tracked, untracked, or ignored code. Parse diagnostics remain visible when structural results may be incomplete.
refs — binding-aware references
refs distinguishes binding-proven references, name matches, and unresolved candidates. Cursor scope asks the language provider for one exact binding; unscoped mode exposes every truth tier. Shadowed locals, imports, Python symbols, and provider-recognized override relations stay separated or connected according to semantic evidence.
Results report their semantic provider and project authority, making completeness visible before a refactor.
rename — proven semantic rename
rename defaults to a dry run with summary, sample, and full detail levels. Before apply, it recomputes the plan against current files; every same-name candidate must be proven part of the rename relation or proven to belong to another binding. Unresolved candidates and semantic collisions block the transaction.
Strings and comments are opt-in. A successful apply updates the working tree atomically across files and returns fresh anchors.
Language support
| Language or format | Extensions | Capabilities |
|---|---|---|
| JavaScript / JSX | .js, .jsx, .mjs, .cjs |
Structural search, code Structure Maps, parse diagnostics, binding references, semantic rename, Local Symbol Bundles |
| TypeScript | .ts, .mts, .cts |
Structural search, code Structure Maps, parse diagnostics, binding references, semantic rename, Local Symbol Bundles |
| TSX | .tsx |
Structural search, code Structure Maps, parse diagnostics, binding references, semantic rename, Local Symbol Bundles |
| Python | .py, .pyi |
Structural search, code Structure Maps, parse diagnostics, binding references, semantic rename, Local Symbol Bundles |
| Markdown | .md |
Heading-based Structure Maps |
| JSON / JSONC | .json, .jsonc |
Data-structure maps |
| YAML | .yaml, .yml |
Data-structure maps |
| TOML | .toml |
Data-structure maps |
JavaScript and TypeScript semantics use the TypeScript Language Service. Python semantics use the bundled Pyright language server. Semantic results state whether their reference closure is project-complete or degraded; a syntax match or matching spelling is not silently promoted to a binding.
search, refs, and rename share Git-aware file-set controls. By default they include tracked files and untracked non-ignored files. cached, others, and ignored can narrow or expand that set; ignored: true requires others: true.
Shell reducer — deterministic, evidence-preserving output
The shell reducer registers no model-callable tool. It intercepts Pi's bash result after execution without changing the command, timeout, working directory, or environment.
Small output passes through byte-for-byte. Large multiline output keeps a bounded head and tail with an exact omission seam; long single lines use a middle clip with their original character count. Exit and timeout status remain explicit. A conservative generic reducer handles arbitrary output, while specialized reducers recognize pinned output grammars for:
- Vitest, Jest, and pytest
- TypeScript, esbuild, and Vite builds
- npm and pnpm installs
- Git diff and log
- ESLint and Biome
A specialized grammar mismatch falls back to generic reduction. Recognized output is marked degraded when the upstream reporter has already discarded information.
Before reduction, the extension attempts to store the raw output under <Pi agent dir>/io-tools/evidence/<session>/; the reduced result reports the recovery path and size. Evidence is a local recovery artifact, not secret storage: it can contain credentials or other sensitive bytes printed by a command, and the extension does not perform general secret classification or redaction.
Configuration
Use the interactive settings editor:
/io-tools-settings
/io-tools-settings global
/io-tools-settings project
Settings are sparse JSON overrides. Their locations are:
Global: <Pi agent dir>/io-tools/settings.json
Project: <working directory>/.pi/io-tools/settings.json
Project values override global values, which override schema defaults. Project settings are loaded only after the project is trusted; run /trust and restart Pi after establishing trust.
Example:
{
"fileTools": {
"read": {
"defaultMaxLines": 400
},
"write": {
"callRecordInContext": "full"
}
},
"shellReducer": {
"reducers": {
"git": false
}
}
}
{
"fileTools": {
"enabled": true,
"relocationWindowLines": 50,
"relocationSimilarityThreshold": 0.8,
"read": {
"defaultMaxLines": 250,
"defaultMaxBytes": 16384,
"smallFileGraceMultiplier": 1.5,
"maxLineChars": 2000
},
"edit": {
"anchorMismatch": {
"maxNearestHashMatches": 3,
"maxSimilarLineSuggestions": 3,
"contextLines": 2
},
"changeRegionContextLines": 2,
"changeRegionMaxLines": 40
},
"write": {
"fullContentMaxLines": 1000,
"fullContentMaxBytes": 32768,
"headLines": 50,
"tailLines": 10,
"callRecordInContext": "elide"
},
"localBundleBudget": {
"maxSymbols": 5,
"maxSourceLines": 160,
"maxBytes": 16384
},
"searchResultBudget": {
"maxMatches": 100,
"maxVisibleLines": 300,
"maxBytes": 32768
},
"renamePlanBudget": {
"maxFiles": 50,
"maxRegions": 100,
"maxVisibleLines": 300,
"maxBytes": 32768
}
},
"shellReducer": {
"enabled": true,
"passthrough": {
"maxLines": 80,
"maxBytes": 8192
},
"outputBudget": {
"maxVisibleLines": 200,
"maxVisibleBytes": 16384
},
"qualityGate": {
"minSavingsRatio": 0.01
},
"reducers": {
"generic": true,
"testRunner": true,
"build": true,
"packageManager": true,
"git": true,
"lint": true
},
"evidence": {
"ttlDays": 7,
"maxFileBytes": 134217728,
"maxSessionBytes": 1073741824
}
}
}
Unknown keys, invalid types, and out-of-range values are rejected explicitly. Cross-field errors disable only the affected domain; the extension does not silently replace invalid configuration with defaults.
Security and limitations
Pi packages execute with the user's full system permissions. Review the source before installing it. These tools are not a sandbox, and file mutations affect the real filesystem.
- Text tools accept UTF-8 text; binary and invalid UTF-8 input is rejected.
readpreserves Pi's image attachment behavior rather than attempting OCR. - Structural search is syntax-only. Binding claims require TypeScript Language Service or Pyright evidence.
- Specialized shell reducers accept only their pinned grammar shapes and otherwise fall back to generic reduction.
- Evidence retention defaults to seven days, 128 MiB per file, and 1 GiB per session. Setting
ttlDaysto0disables age-based cleanup. - Disabling
fileTools.enabledremoves all seven replacement tools. DisablingshellReducer.enabledleavesbashresults untouched.
Please use GitHub Issues for bugs and feature requests. Focused pull requests are welcome; see CONTRIBUTING.md and open an issue first for substantial behavioral changes.
Acknowledgements
- Pi provides the extension and package runtime.
- pi-readseek informed the anchor and hashline behavior. This implementation is an independent TypeScript rewrite.
- Hypa informed deterministic reduction and Evidence concepts. This package contains no Hypa source code, adapted code, binaries, or runtime dependencies; its reducers are independently implemented in TypeScript and do not rewrite shell commands.
See THIRD_PARTY_NOTICES.md for dependency and algorithm-lineage notices.
License
MIT © 2026 daoguademeng.