@realvendex/pi-loop
Pi coding-agent extension that adds a /loop command — run a prompt repeatedly with convergence detection, rich stop conditions, lifecycle hooks, a live TUI panel, and desktop notifications.
Package details
Install @realvendex/pi-loop from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@realvendex/pi-loop- Package
@realvendex/pi-loop- Version
1.0.2- Published
- Jul 12, 2026
- Downloads
- 55/mo · 55/wk
- Author
- realvendex
- License
- MIT
- Types
- extension
- Size
- 85.9 KB
- Dependencies
- 0 dependencies · 0 peers
Pi manifest JSON
{
"extensions": [
"./extensions"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-loop
A Pi coding-agent extension that adds a
/loop command — run a prompt repeatedly, confirming between rounds, exactly like the
Claude Code CLI /loop, but with a richer set of stop conditions, lifecycle hooks, a live
TUI panel, and desktop notifications.
╭────────────────────────────────────────────╮
│ ⟳ /loop iter 3/5 │
│ ███████████████░░░░░ 60% │
│ ⠴ idle 12.3s │
│ tag build │
│ conv ████████░░ 82% │
│ ↳ refactored the loop panel for clarity │
│ ⊘ /loop stop to cancel │
╰────────────────────────────────────────────╯
Features
- Repeat a prompt with optional per-round confirmation (manual mode) or fully unattended (YOLO autopilot).
- Stop conditions: text match, regex match, all-match, identical-reply convergence, fuzzy convergence, single-step similarity threshold, external command success/failure, wall-clock timeout, per-iteration timeout, error markers, and max failures.
- Self-referential prompts via rich templating:
{{n}},{{prev}},{{prev:N}},{{last:N}},{{all}},{{count}},{{ts}}. - Lifecycle hooks (
--on-start/--on-fail/--on-stop/--on-iter) to drive external automation (CI, notifications, logging). - Rich live TUI panel: animated boxed status with progress bar, phase indicator, ETA, convergence bar, and a last-reply preview.
- Resilience: exponential-backoff retries on error markers, a bounded default turn timeout (so a stuck agent can never hang the loop forever), and a single-loop concurrency guard.
- Run logs: every loop writes a JSON log to
~/.pi/loops/(last 20 kept); browse them withlogs,stats,show. - Presets: save/load named loop configs;
/loopwith no args resumes the last run. - Finish signals:
--notify(OS toast) and--sound(terminal bell).
Requirements
- Pi coding agent installed and running.
- Node.js 18+ (Pi's runtime).
Install
@realvendex/pi-loop is a Pi package: it ships a pi manifest that tells Pi to load index.ts as an extension. Pick one method — do not combine them, or /loop gets registered twice and Pi warns about a duplicate command.
Option A — pi install (recommended)
pi install npm:@realvendex/pi-loop # latest
pi install npm:@realvendex/pi-loop@1.0.1 # or pin a version
Pi installs the package under ~/.pi/agent/npm/ and auto-loads the extension from its pi manifest. Run /reload (or restart Pi) to activate it. Update later with pi update npm:@realvendex/pi-loop.
Option B — git clone
git clone https://github.com/ZachDreamZ/pi-loop /tmp/pi-loop
cp /tmp/pi-loop/extensions/index.ts ~/.pi/agent/extensions/pi-loop/index.ts
Then run /reload (or restart Pi). No build step — Pi loads index.ts directly from the extensions directory.
Option C — npm + manual copy
npm i -g @realvendex/pi-loop
# copy the extension entry into Pi's extension directory
cp "$(npm root -g)/@realvendex/pi-loop/index.ts" ~/.pi/agent/extensions/pi-loop/index.ts
/reload
Local install works too:
npm i @realvendex/pi-loopthen copynode_modules/@realvendex/pi-loop/index.tsinto the extensions directory.
Quick start
/loop "fix the failing tests" --max 5
/loop --yes --until "all tests pass" "refactor the auth module"
/loop "attempt {{n}}: {{prev}}" --max 5 --yes
/loop --yes --until-stable 3 "tweak until output converges"
/loop --until-converged 95 --max 20 "iterate until replies stop changing"
/loop --until-regex "tests:\s+\d+ passing" --yes "run the suite"
/loop --timeout 5m "long autonomous task"
/loop --name deploy --yes "ship it" # tagged run log
/loop --notify --sound --yes --max 5 "do the work" # toast + bell on finish
/loop # resume the last loop
/loop stop # cancel the active loop
Commands
| Command | Description |
|---|---|
/loop "<prompt>" [flags] |
Run a loop (the main command). |
/loop stop |
Cancel the active loop (halts after the current iteration). |
/loop resume |
Re-run the last /loop invocation (also: bare /loop). |
/loop save NAME |
Save the last run's config as a named preset. |
/loop load NAME |
Run a saved preset (alias: /loop run NAME). |
/loop list |
List all saved presets and the last config. |
/loop delete NAME |
Delete a saved preset. |
/loop last |
Print the most recent loop config. |
/loop logs [TAG] |
List recent run logs (most recent first), optionally filtered by a --name tag. |
/loop stats |
Aggregate metrics across all run logs (count, avg iterations, avg duration, stop-reason breakdown). |
/loop show [N] |
View a run log. N = index (1 = most recent), a filename, or a substring. |
/loop preview "<prompt> ...flags>" |
Print the resolved config and every templated prompt (up to 10) without running — great for debugging templates. |
Flags
| Flag | Default | Description |
|---|---|---|
--max N / -n N |
10 |
Maximum iterations. --max 0 = unbounded (runs until a stop condition, --timeout, or /loop stop). |
--until "TEXT" |
— | Stop when the last assistant reply contains TEXT. Repeatable (any match stops). |
--until-regex R |
— | Stop when the last assistant reply matches regex R. Repeatable. Invalid patterns are ignored with a warning. |
--until-all / --all |
off | Require ALL --until texts AND --until-regex patterns to match (default: ANY match stops). |
--until-stable N |
0 |
Stop when the last N consecutive replies are identical (convergence). |
--until-stable-sim P / --stable-sim P |
0 |
Fuzzy convergence: last N replies must be ≥P similar (token-overlap, 0..1) instead of byte-identical. |
--until-converged P / --converge P |
0 |
Stop when the single-step similarity between the last two replies is ≥ P% (0–100). Distinct from --until-stable-sim, which requires a window of N replies. |
--yes / -y / --auto / --yolo |
off | YOLO autopilot: skip per-round confirmation and auto-approve any confirmation surfaced during a turn. Never blocks. |
--delay MS / --every MS |
0 |
Milliseconds to wait between iterations. |
--delay-jitter P |
0 |
Apply ±P% random jitter to --delay (0..100) to avoid rate-limit clumping. |
--timeout 30s|5m|1h |
0 |
Wall-clock cap; loop stops when exceeded (units s/m/h, or bare seconds). |
--iter-timeout 30s|5m|1h |
0 |
Per-iteration cap; if a single turn exceeds it, the loop stops. When unset, a 30-minute default bound still applies so a stuck turn can't hang the loop forever. |
--stop-on-error |
off | Stop if the last assistant reply shows an error marker. |
--retry-on-error N / --retry N |
0 |
Retry a failed iteration up to N times (nudges the agent to try a different approach) before stopping. |
--retry-delay MS |
1000 |
Base delay between retries; grows exponentially (MS, 2·MS, 4·MS … capped at 60s). |
--max-failures N |
0 |
Stop after N consecutive failed iterations (error marker with no retry left, and --stop-on-error not set). |
--until-cmd C / --until-command C |
— | Stop when shell command C exits 0 (e.g. run your test suite; loop until it passes). Checked once before iteration 1 and after every iteration; 120s timeout (override with --until-cmd-timeout). |
--until-cmd-fail C / --until-command-fail C |
— | Inverse: stop when shell command C exits non-zero (e.g. loop while a server is up; stop the moment it goes down). |
--until-cmd-timeout T |
120s |
Timeout for --until-cmd / --until-cmd-fail (units s/m/h, or bare ms). |
--on-start CMD |
— | Run shell CMD once, just before iteration 1 (skipped if a pre-flight check already ends the loop). Tokens: {{i}} {{max}} {{name}}. |
--on-fail CMD |
— | Run shell CMD after each failed iteration. Tokens: {{i}} {{reply}} {{reason}}. |
--on-stop CMD |
— | Run shell CMD once when the loop ends (any reason). Tokens: {{i}} {{reason}} {{iterations}} {{reply}}. |
--on-iter CMD |
— | Run shell CMD after every completed iteration. Tokens: {{i}} {{reply}} {{reason}}. |
--hook-timeout T |
30s |
Timeout for hook commands; a hung hook is killed and reported as a warning, never aborting the loop. |
--error-markers A|B |
built-ins | Custom pipe-delimited error markers (overrides the built-in list). |
--name TAG |
— | Tag the run-log filename (e.g. loop-deploy-<ts>.json) for easy lookup. |
--quiet / -q |
off | Suppress per-iteration start notices. |
--notify |
off | Show an OS notification (macOS / Linux / Windows) when the loop finishes. |
--sound |
off | Play a terminal bell when the loop finishes. |
Prompt templating
Before each send, these tokens are substituted into the prompt (unknown tokens are left untouched):
| Token | Substituted with |
|---|---|
{{n}} / {{N}} / {{i}} |
1-based iteration number |
{{max}} / {{MAX}} |
Total iteration cap, or ∞ when --max 0 (unbounded) |
{{prev}} / {{prev1}} |
The previous assistant reply (whitespace collapsed, truncated to 500 chars) |
{{prev:N}} |
The Nth-previous reply (2 = the one before {{prev}}) |
{{last:N}} |
The last N characters of the previous reply |
{{all}} |
All prior replies joined by --- |
{{count}} |
Number of completed prior iterations |
{{ts}} |
Current timestamp at render time (ISO 8601, fresh per iteration) |
Example — each iteration builds on everything that came before:
/loop --yes --max 8 "Iteration {{n}} of {{max}} ({{count}} prior attempts).\nPrior work:\n{{all}}\nNow improve it."
Lifecycle hooks
Hooks let a loop drive external automation at key moments. Each hook is a shell command;
Pi substitutes {{token}} vars before running it and reports the output via a notification.
A hook that errors or times out is reported as a warning and never stops the loop.
| Hook | When it fires | Available tokens |
|---|---|---|
--on-start CMD |
Once, before iteration 1 (only if the loop actually runs) | {{i}} (=0), {{max}}, {{name}}, {{reason}} |
--on-fail CMD |
After each failed iteration (error marker, no retry remaining) | {{i}}, {{n}}, {{max}}, {{name}}, {{reason}} (=error-marker), {{reply}}, {{prev}} |
--on-stop CMD |
Once, when the loop ends (any reason) | {{i}}, {{n}}, {{max}}, {{name}}, {{reason}} (stop cause), {{iterations}}, {{reply}}, {{prev}} |
--on-iter CMD |
After every completed iteration (next-iteration path) | {{i}}, {{n}}, {{max}}, {{name}}, {{reason}} (=iteration), {{reply}}, {{prev}} |
Shared hook tokens: {{i}}/{{n}} (iteration), {{max}} (cap or ∞), {{name}} (tag),
{{reason}} (stop cause: max, until, error, timeout, cmdfail, maxfailures,
stable, converged, …), {{reply}} (latest reply), {{prev}} (prior reply),
{{iterations}} (total run). Control hook runtime with --hook-timeout (default 30s).
/loop --yes --max 5 --on-stop "curl -s ntfy.sh/mytopic -d 'loop done: {{reason}}'" "build the thing"
/loop --yes --until-cmd "npm test" --on-fail "echo 'FAILED iter {{i}}: {{reply}}' >> /tmp/loop-fails.log" "fix the tests"
/loop --yes --max 3 --on-start "echo loop started for {{name}}" --name nightly "run the job"
Behavior
- Manual mode (default): after each iteration Pi asks you to continue. Decline (or press Escape) to stop.
- Autopilot mode (
--yes/--auto/--yolo): runs unattended and auto-approves every prompt. Still stops on--max,--timeout,--iter-timeout, a--untilmatch, convergence, or an error marker when--stop-on-erroris set. - Cancel anytime: send
/loop stop. The loop halts after the current iteration completes (it never kills a turn mid-flight). - A rich live TUI panel shows the current iteration, progress, phase, ETA, convergence, and last-reply snippet. The final summary reports the stop reason, total time, average time per iteration, and convergence percentage.
- Every loop writes a JSON run log to
~/.pi/loops/(last 20 kept).
Notes
- Only one loop runs at a time. Starting a new
/loopwhile one is active is blocked until you send/loop stop. - The loop sends real user messages via
pi.sendUserMessage, so the agent behaves exactly as if you typed the prompt each round. - In non-interactive contexts (no UI), manual confirmation is unavailable, so the loop automatically switches to autopilot with a warning.
Development
git clone https://github.com/ZachDreamZ/pi-loop
cd pi-loop
npm install # pulls typescript + @types/node for type-checking
npm run typecheck # tsc --noEmit (validates the extension in isolation via a type shim)
extensions/index.ts is the entire extension. Pi loads it directly (no build step). The type shim in
shims/pi-coding-agent.d.ts lets tsc type-check the file without the Pi binary. CI runs
npm run typecheck on every push/PR.
License
MIT © ZachDreamZ