@sting8k/pi-utils
Utility extensions for the Pi coding agent: background shell (shell-bg) with bash search routing, script-mode edit, and the skills write layer (skill_write)
Package details
Install @sting8k/pi-utils from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@sting8k/pi-utils- Package
@sting8k/pi-utils- Version
0.10.0- Published
- Oct 28, 2026
- Downloads
- 875/mo · 360/wk
- Author
- sting8k
- License
- MIT
- Types
- extension
- Size
- 245 KB
- Dependencies
- 3 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"./extensions/shell-bg.ts",
"./extensions/edit.ts",
"./extensions/read.ts",
"./extensions/skill-write.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-utils
Utility extensions for the Pi coding agent: a background-aware bash, script-mode edit, a read that keeps images light, and skill_write for agents that maintain their own skills.
Features
bash(replaces the built-in): commands still running after 30s move to the background and their result arrives later, so the agent's turn is not blocked- Search routing: plain
rg/grep/findcommands run on capped search cores that include gitignored files shell_status/shell_kill: list, inspect, and stop background jobs; a live widget shows running onesedit(replaces the built-in): the model sends a script plus the files it may touch and gets the diff back; failures roll backread(replaces the built-in): images over 1568px or 200 KB are compressed before they reach the model;original: truesends Pi's normal sizeskill_write: create, patch, delete, or moveSKILL.mdfiles, with a compact skills index in the system prompt
Installation
pi install npm:@sting8k/pi-utils
Search routing needs rg on PATH or in ~/.pi/agent/bin.
bash and background jobs
bash keeps Pi's shell, cwd, and env, and changes only the lifecycle:
| Situation | What happens |
|---|---|
| Finishes quickly | Returns normally |
| Still running after 30s | Moves to the background as bg-1; the result is delivered when it finishes |
background: true |
Starts in the background right away |
timeout: N |
Kills the whole process tree after N seconds |
shell_status() # totals + newest 10 jobs, running first
shell_status(id="bg-2") # one job: output so far, or the final result
shell_kill(id="bg-2") # stop it and its process tree
/shell-bg [kill bg-2] # same, as a slash command
Finished jobs arrive in the conversation as <shell_bg_result> and wake the agent. Jobs that finish during a run arrive together in one message. Under headless pi -p nothing arrives after the turn ends, so collect jobs with shell_status before it does.
Search routing
A standalone search command sent to bash runs on the search cores instead of a raw shell. Output is capped, and when it hits the cap the full result is written to a temp file. Rows are path:line: text, so the line number feeds straight into read's offset.
bash(command="rg -i preset src") # grep core
bash(command="find src -name '*.ts'") # glob core, sorted by mtime, newest last
Pipes, redirects, $, unknown flags, or anything else the matcher cannot map exactly run in real bash unchanged. Wrappers listed in bashRouter.unwrapPrefixes (default ["rtk"]) are stripped before matching.
edit
| Field | Required | Notes |
|---|---|---|
code |
yes | python or node script, passed on stdin |
paths |
yes | every file the script may touch |
lang |
no | python (default) or node |
timeout |
no | seconds (default 10); kills the process tree and rolls back |
pathsis the boundary. Only declared files are snapshotted, diffed, and rolled back. Writes elsewhere are not seen.- Failures roll back. A nonzero exit, timeout, or abort restores every declared file and deletes the ones the script created.
- No-op runs warn. A script that changed nothing returns
no declared file changed. - Not a sandbox. The script runs with your user's permissions.
read
Pi's read sends images up to 2000px and 4.5 MB. The whole conversation, every image included, is resent on each request, so a few large images slow every later response. pi-utils read caps images at 1568px on the long edge and 200 KB. Pi's resizer scales the image, and mozjpeg (4:4:4, full-resolution color) encodes it once at the highest quality up to 80 that fits. An image that already fits is sent untouched, and one that cannot fit at quality 40 is scaled down further.
read(path="shot.png") # 3520x2384 PNG -> 1568x1062 JPEG, 57 KB (Pi's read: 1.1 MB)
read(path="shot.png", original=true) # what Pi's read would send
A compressed image comes with a note telling the agent to use original: true when it needs finer detail (left out when the model cannot see images, since a retry would not help it). Text files read exactly as in Pi. Limits the model declares itself win when they are smaller.
skill_write
skill_write manages skills under ~/.pi/agent/skills/<category>/<name>/SKILL.md. Each change is snapshotted and rolled back on failure, and a skill must be read before it can be changed. It also:
- replaces Pi's
<available_skills>list with a compact index, built once per session so the system prompt stays the same across turns. Small skill sets list every description; large ones list names by category plus the 15 most-used - hides skills whose
platforms,requires, ordirsfrontmatter does not match - suggests up to 3 relevant skills when the prompt matches them (
skills.hint) - on
create, lists the 3 existing skills closest to the new one, so the agent can merge into one that already covers the lesson - reminds the agent to save lessons every 10 iterations (
skills.nudgeInterval,0turns it off)
Settings
~/.pi/agent/pi-utils.json is created with these defaults on first start. Missing keys fall back to defaults; a broken file falls back entirely, with a warning.
{
"fsSearch": {
"noIgnore": true,
"globMaxResults": 100,
"grepMaxMatches": 250,
"grepMaxLineBytes": 2000,
"rawOutputMaxBytes": 20971520,
"timeoutMs": 30000,
"graceMs": 3000
},
"shellBg": {
"autoBackgroundMs": 30000,
"tailBytes": 8192,
"killGraceMs": 3000
},
"bashRouter": { "unwrapPrefixes": ["rtk"] },
"edit": { "lang": "python", "timeoutSec": 10 },
"read": { "imageMaxEdge": 1568, "imageMaxBytes": 204800 },
"skills": {
"index": "smart",
"coreLimit": 15,
"hint": true,
"nudgeInterval": 10
},
"disabledTools": []
}
fsSearch: limits for searches routed frombash(result caps, line length, timeout). These are not settings for separategrep/globtools, which were removed in 0.7.0.shellBg: when a command moves to the background, how much output a result shows, and how long a kill waits.bashRouter: wrappers to strip before matching a search command.read: image caps for reads withoutoriginal: true.imageMaxBytescounts the base64 payload sent to the model.
disabledTools turns off individual tools: bash, shell_status, shell_kill, edit, read, skill_write. A trailing * works as a wildcard ("shell*").
bash,edit, orread: Pi's built-in version takes over. Disablingbashalso removes the job tools and the widget.skill_write: turns off the tool, the index, and the reminder.
Styling
If @sting8k/pi-droid-styling is installed, the tools use its boxed rendering. Otherwise Pi's default rendering is used.
Development
git clone https://github.com/sting8k/pi-utils && cd pi-utils && bun install
pi -e ./extensions/shell-bg.ts -e ./extensions/edit.ts -e ./extensions/skill-write.ts
bun run check && bun test
Related Work
- pifydev/shell-background (MIT): the design
shell-bgfollows @earendil-works/pi-coding-agent: the host; the grep core is a fork of its streaming grep- ripgrep: the engine behind routed searches