@aliou/pi-toolchain
v0.3.2
Published
Opinionated toolchain enforcement for pi. Transparently rewrites commands to use preferred tools instead of blocking and forcing retries.
Maintainers
Readme
Toolchain
Opinionated toolchain enforcement for pi. Transparently rewrites commands to use preferred tools instead of blocking and forcing retries.
Installation
Install via the pi-extensions package:
pi install git:github.com/aliou/pi-extensionsOr selectively in your settings.json:
{
"packages": [
{
"source": "git:github.com/aliou/pi-extensions",
"extensions": ["extensions/toolchain"]
}
]
}Or from npm:
pi install npm:@aliou/pi-toolchainFeatures
Rewriters (transparent, via spawn hook)
These features rewrite commands before shell execution. The agent never sees that the command was changed.
- enforcePackageManager: Rewrites
npm/yarn/buncommands to the selected package manager. Also handlesnpx->pnpm dlx/bunx. - rewritePython: Rewrites
python/python3touv run pythonandpip/pip3touv pip. - gitRebaseEditor: Injects
GIT_EDITOR=trueandGIT_SEQUENCE_EDITOR=:env vars forgit rebasecommands so they run non-interactively.
Blockers (via tool_call hooks)
These features block commands that have no clear rewrite target.
- preventBrew: Blocks all
brewcommands. Homebrew has no reliable 1:1 mapping to Nix. - preventDockerSecrets: Blocks
docker inspectand commondocker execenv-exfiltration commands (env,printenv,/proc/*/environ). - python confirm (part of rewritePython): When python/pip is used outside a uv project (no
pyproject.toml), shows a confirmation dialog. Also blockspoetry/pyenv/virtualenvunconditionally.
Settings Command
Run /toolchain:settings to open an interactive settings UI with two tabs:
- Local: edit project-scoped config (
.pi/extensions/toolchain.json) - Global: edit global config (
~/.pi/agent/extensions/toolchain.json)
Use Tab / Shift+Tab to switch tabs. Boolean settings and the package manager can be toggled directly.
Configuration
Configuration is loaded from two optional JSON files, merged in order (project overrides global):
- Global:
~/.pi/agent/extensions/toolchain.json - Project:
.pi/extensions/toolchain.json
Configuration Schema
{
"enabled": true,
"features": {
"enforcePackageManager": false,
"rewritePython": false,
"preventBrew": false,
"preventDockerSecrets": false,
"gitRebaseEditor": true
},
"packageManager": {
"selected": "pnpm"
}
}All fields are optional. Missing fields use the defaults shown above.
Feature Defaults
| Feature | Default | Description |
|---|---|---|
| enforcePackageManager | false | Opt-in. User must pick a manager. |
| rewritePython | false | Opt-in. User must have uv set up. |
| preventBrew | false | Opt-in. Machine-specific. |
| preventDockerSecrets | false | Opt-in. Blocks commands that can exfiltrate container env secrets. |
| gitRebaseEditor | true | On by default. Always safe. |
Examples
Enforce pnpm and block brew:
{
"features": {
"enforcePackageManager": true,
"preventBrew": true
},
"packageManager": {
"selected": "pnpm"
}
}Enable python/uv rewriting:
{
"features": {
"rewritePython": true
}
}How It Works
Rewriters vs Blockers
The extension uses two pi mechanisms:
Spawn hook (
createBashToolwithspawnHook): Rewrites commands before shell execution. The agent sees the output of the rewritten command but doesn't know it was changed. Used for package manager, python/uv, and git rebase.tool_call event hooks: Block commands entirely. The agent sees a block reason and retries with the correct command. Used for brew (no rewrite target) and python outside uv projects (needs confirmation).
Execution Order
- Guardrails
tool_callhooks run first (permission gate, env protection) - Toolchain
tool_callhooks run (brew blocker, python confirm) - If not blocked, toolchain's bash tool runs with spawn hook (rewrites command)
- Shell executes the rewritten command
AST-Based Rewriting
All rewriters use structural shell parsing via @aliou/sh to identify command names in the AST. This avoids false positives where tool names appear in URLs, file paths, or strings. If the parser fails, the command passes through unchanged -- a missed rewrite is safe, a false positive rewrite corrupts the command.
Migration from Guardrails
If you were using preventBrew, preventPython, or enforcePackageManager in your guardrails config:
- Install
@aliou/pi-toolchain - Create
.pi/extensions/toolchain.jsonwith the equivalent config - Remove the deprecated features from your guardrails config
The guardrails extension will continue to honor these features with a deprecation warning until they are removed in a future version.
