@koltmcbride/pi-loop

A pi coding-agent extension that runs a prompt repeatedly on a timer, pi event, or self-paced (Claude Code-style /loop)

Packages

Package details

extension

Install @koltmcbride/pi-loop from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@koltmcbride/pi-loop
Package
@koltmcbride/pi-loop
Version
0.2.0
Published
May 30, 2026
Downloads
1,494/mo · 65/wk
Author
koltmcbride
License
MIT
Types
extension
Size
51.4 KB
Dependencies
0 dependencies · 3 peers
Pi manifest JSON
{
  "extensions": [
    "./loop.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-loop

A pi extension that runs a prompt repeatedly — on a fixed timer, when a pi event fires, or at the agent's own pace. Modelled on Claude Code's /loop.

Overview

License: MIT pi-package Version

Schedule a prompt to run repeatedly inside pi. An interval is parsed at the command layer into a cron schedule and run by a self-re-arming timer, so the loop keeps going on its own — the model is never responsible for keeping it alive. A self-paced mode is kept for "let the model decide when there's nothing left to do."

What changed in 0.2.0

Earlier versions had a single self-paced mode: the model had to call a wakeup tool at the end of every turn or the loop ended. That meant a turn ending on a summary silently killed the loop, and an interval like 15m written in the prompt was never actually a cadence — just text.

0.2.0 makes a parsed interval authoritative and timer-driven, adds event and hybrid triggers, multiple concurrent loops, and persistence that restores unexpired loops on resume. Self-paced remains as a second mode.

Features

  • Fixed-interval loops/loop 15m <prompt> parses the interval into cron and runs it on a self-re-arming timer. Continuation is the default.
  • Self-paced loops/loop <prompt> (no interval) fires once, then continues only if the model calls schedule_loop_wakeup. It may end the loop by not calling it.
  • Event & hybrid triggers — fire on a pi event (e.g. tool_execution_end, turn_end, monitor:done) instead of polling, or combine cron + event with debounce.
  • Multiple loops — run several at once; manage with LoopCreate / LoopList / LoopDelete or /loop list.
  • Persistence — loops are stored under .pi/loops and restored, if unexpired, on --resume/--continue.
  • Safety caps — per-loop maxFires and an automatic 7-day expiry; jittered fire times avoid API stampedes.
  • Read-only mode — restrict a loop's fires to read/inspection tools.
  • Live status — a footer indicator and widget list active loops with next-fire countdowns.

Installation

pi install npm:@koltmcbride/pi-loop
# or
pi install git:github.com/kolt-mcb/pi-loop@v0.2.0

Verify it's loaded with pi list.

Quick start

/loop 5m check if the deployment finished and report what happened

Fixed 5-minute loop. Runs until you stop it, 7 days pass, or it hits a fire cap.

/loop check whether CI passed and address review comments

Self-paced: the model works, then decides whether to continue via schedule_loop_wakeup (and at what delay).

/loop stop          # stop all active loops
/loop stop 3        # stop loop #3
/loop list          # show / manage active loops

Usage

/loop command

Input Behaviour
/loop 15m <prompt> Fixed-interval (cron) loop. Interval may also trail: <prompt> every 2 hours.
/loop 0 9 * * 1-5 <prompt> Full 5-field cron schedule.
/loop <prompt> Self-paced loop (model-driven cadence).
/loop list List/manage active loops.
/loop stop [id] Stop all loops, or one by id.

Intervals use s / m / h / d. Sub-minute rounds up to one minute (cron's floor); odd intervals like 7m snap to the nearest clean cron step and the loop tells you what it picked.

Tools (for the agent)

Tool What it does
LoopCreate Schedule a loop on a cron timer, a pi event, or a hybrid of both. Supports recurring, readOnly, maxFires, filter.
LoopList List loops with ids, triggers, fire counts, next-fire times.
LoopDelete Delete a loop, or action="pause" to keep it without firing.
schedule_loop_wakeup Continue the active self-paced loop; optional delaySeconds. Omit to end it.

Trigger types: cron (5m, 1h, 0 9 * * 1-5), event (any pi event-bus channel; lifecycle events tool_execution_start/end, turn_start/end, agent_start/end, message_end are bridged through), or hybrid (both, debounced).

Behaviour notes

  • Fires land between turns. Each fire is delivered as a follow-up message, so it waits for the current turn to finish. A recurring fire is skipped while a message is already queued, so ticks never stack.
  • Takeover. Typing while a self-paced loop is waiting ends it (you took over). Fixed and event loops keep running across your messages until you /loop stop them.
  • No catch-up. If fires were missed while busy, the loop fires once when idle, not once per missed interval.

Configuration

Variable Effect Default
PI_LOOP off disables persistence (in-memory only); an absolute or relative path sets a custom store file .pi/loops/loops-<sessionId>.json

Constants at the top of loop.ts / src/: status tick interval, default hybrid debounce, and the bridged lifecycle event list. Caps: 25 active loops, 7-day expiry.

Development

npm install
npm run typecheck   # tsc --noEmit
npm test            # node:test via tsx — covers parsing, cron, jitter

Source layout:

File Responsibility
src/types.ts Loop/trigger types.
src/loop-parse.ts parseInterval, extractInterval, cron math, jitter (pure, tested).
src/store.ts Loop registry + JSON persistence.
src/scheduler.ts Self-re-arming cron timers.
src/triggers.ts Event/hybrid subscriptions + debounce.
loop.ts Entry: command, tools, fire→message bridge, status widget, lifecycle.

License

MIT