pi-grow-loop is a semantic loop-engineering layer for Pi. It pairs the portable while-true worker protocol with a visible, interruptible scheduler to advance concrete work from project state or an explicit scoped outcome.
The agent owns scope, evidence, priority, safety, and the decision to continue or stop; the runtime only schedules the next turn, while the operator retains normal conversational control. There is no hidden queue, fixed workflow, regex latch, or runtime state machine replacing agent judgment.
Requires Pi 0.80.4 or newer for the settled-agent lifecycle event.
Install from npm:
pi install npm:@llblab/pi-grow-loopOr install from git:
pi install git:github.com/llblab/pi-grow-loopThen focus Pi on trustworthy open work or provide a concrete multi-slice outcome and ask for continuation:
grow loop
The agent should run one bounded while-true slice, report what changed or what was proven, and schedule another visible turn only if useful work remains.
Use pi-grow-loop when the execution shape has all of these properties:
- A concrete delegated scope or outcome.
- A truthful canonical work surface that exists or can be bootstrapped from that outcome.
- Multiple independently useful bounded slices with separate validation evidence.
- Operator-visible continuation boundaries that provide useful opportunities to redirect or stop.
- Safe actionable or preparable work remains after the current slice.
The vocabulary, apparent size, and number of internal steps do not select the protocol. Decomposing an explicit requested outcome into a canonical backlog is not inventing work. Harvesting unrelated improvements merely to keep the loop alive is. If neither an existing surface nor a concrete outcome exists, the correct result is a stop proof or a request for the missing scope.
/goal is the nearest mental model, but it solves a different problem. It creates a goal-shaped session around a declared outcome. pi-grow-loop selects an iterative execution shape and keeps its source of truth in a canonical open-work surface, whether discovered or bootstrapped from an explicit scoped outcome.
| Dimension | /goal |
pi-grow-loop |
|---|---|---|
| Starting point | A declared objective | Existing project evidence or an explicit scoped outcome |
| Planning mode | Decompose a goal-shaped session | Bootstrap or reconcile a canonical open-work surface |
| Agent question | "How do we reach this outcome?" | "What is the next safe useful slice?" |
| Runtime shape | Goal/session frame | Normal visible Pi turns |
| Continuation | Driven by the goal session | Re-decided after each while-true checkpoint |
| Work shape | Goal-organized initiative | Independently useful slices with visible validation boundaries |
The distinction is session shape and source of truth: /goal owns a goal object; pi-grow-loop has no goal object and advances a canonical backlog one visible checkpoint at a time. An explicit outcome may seed that backlog, but only requested work belongs there.
lock the user-focus scope
→ checkpoint current reality
→ reconcile the open-work surface
→ assemble one bounded validation cohort
→ execute tasks with focused checks
→ validate the cohort proportionally
→ hand off evidence and remaining state
→ decide once: stop, or schedule one next visible turn
The selected scope stays stable across iterations unless the operator redirects it or verified reality proves that a different surface governs the same work. The runtime does not decide what matters; the skills do.
Relevant project-local delivery instructions may explicitly declare a feature's source of open work:
Canonical open work: ./BACKLOG.mdRelative paths resolve from the declaring instruction. while-true gives a trustworthy declaration precedence over filename-based discovery without knowing which skill or methodology produced it. It does not mine procedural skill prose for tasks or scan unrelated skills merely to find available work.
Resolution remains scope-locked: external references must recover precise current work, scope-mismatched declarations are ignored, root plans may index a feature-local surface without duplicating tasks, and stale or missing owners must be repaired from evidence rather than replaced with unrelated work. Competing relevant declarations stop for the smallest ownership decision when project evidence cannot select one.
A project-local knowledge or support skill without a trustworthy declaration remains context, never a task source. while-true does not infer work from prose, examples, insights, historical delivery sections, or lifecycle language. The same skill may later declare new canonical open work when its feature evolves; discovery follows current evidence rather than producer identity.
The plain-text declaration remains intentionally sufficient: real composition runs require scope and ownership validation, not a producer registry, lifecycle marker, or structured metadata layer. Additional syntax should appear only after reproducible ambiguity proves this contract insufficient.
while-trueskill — the portable worker protocol. It assesses reality, reconciles backlog/plan state, and executes one bounded validation cohort. By default it batches several independent low-coupling tasks, falsifies each task cheaply, runs expensive shared validation once, and hands off evidence. Coupled, ordered, large, high-risk, or diagnostically ambiguous work runs as a single-task cohort. It knows nothing about Grow Loop or its runtime.grow-loopskill — the continuation meta-protocol. It locks the relevant scope, interprets recent user intent, consumes the worker handoff, and decides exactly once whether another iteration should run.grow_looptool — the scheduler. It waits briefly, shows status, and sends the next visible Pi prompt. It takes no arguments.
Protocol selection happens before worker execution:
explicit while-true → one portable worker pass → handoff to caller
explicit grow-loop → Grow Loop → while-true → decide → grow_loop or stop
one coherent change → ordinary one-shot execution
multi-slice outcome → Grow Loop → bootstrap backlog → bounded iterations
runtime continuation prompt: while true | grow loop
Explicit protocol names are exact overrides: asking for while-true never silently expands into Grow Loop. When no protocol is named, automatic routing follows execution topology: one coherent change remains one-shot, while a concrete outcome with independently useful validated slices may select Grow Loop. Concrete tasks may illustrate either shape, but their verbs and categories never act as activation predicates.
Multiple internal steps do not by themselves require Grow Loop. Use ordinary one-shot execution when those steps form one coherent change that can be validated and reported at one natural boundary. Use Grow Loop when a concrete delegated outcome benefits from multiple independently useful slices, each with its own validation evidence and a visible opportunity for the operator to redirect or stop. This is semantic judgment, not a keyword classifier or consent ceremony.
Each visible iteration has one checkpoint boundary:
while-trueexecutes at most one bounded validation cohort. The cohort batches independent low-coupling tasks by default and falls back to one task when ordering, overlap, size, risk, or diagnosis requires it.- Each cohort task gets a cheap focused falsifier before the next task; expensive type, build, integration, context, or live validation runs once after the retained cohort.
- The worker hands off the locked scope, cohort membership, plan transitions, per-task evidence, shared validation result, highest-value remaining item, actionability, blocker, and exact unblocker.
grow-loopgives latest operator intent precedence over repository availability and compares the checkpoint with the previous iteration to reject repeated no-ops.- If continuation remains safe and valuable, it calls
grow_loopexactly once and ends the turn. Otherwise it does not call the tool and returns a stop proof.
Bounded does not mean one file, command, internal step, backlog item, or tiny edit. It means one validation cohort whose task-level failures remain attributable, followed by shared validation and an operator-visible continuation boundary.
A standalone while-true invocation ends at that handoff. Only a previously selected grow-loop meta-protocol may consume it as a continuation checkpoint and schedule another turn.
grow_loop is intentionally narrow:
- Waits until Pi is idle and no user messages are pending.
- Shows a fixed 3-second interrupt countdown.
- Sends the compact prompt
while true | grow looponly if Pi is still idle. - If Pi becomes busy during the countdown, returns to deferred waiting instead of queueing a hidden follow-up.
- Shows loop status only while it is actively carrying the rhythm.
- Clears pending scheduling and hides loop status when any user prompt arrives, including prompts injected by another extension; only the scheduler's exact expected continuation prompt preserves the rhythm.
The tool never blocks future calls. Whether to continue belongs to the agent and skills, not to a runtime latch, regex, slash command, or hidden state machine.
- No status — no active loop rhythm, or the operator took the turn.
loop ∞Nwarning — the next loop prompt is armed and waiting for idle/no pending messages.loop 3.0scountdown — Pi is idle and the interrupt window is open.loop ∞Ndim — the compact loop prompt was sent for this iteration.
N is monotonic within the current extension instance. Active status clears when the scheduled agent run fully settles without arming a successor, so automatic retry or compaction recovery does not produce a false idle state. There is no loop stopped or loop paused status; absence of loop status means the runtime rhythm is no longer active.
Any user prompt except the scheduler's exact expected continuation prompt exits the active runtime rhythm. This includes operator input delivered through Telegram, RPC bridges, or other extensions:
Runtime: loop 3.0s or loop ∞2
User: What changed?
Runtime: hides loop status and cancels pending scheduling
Agent: answers, stops, changes direction, or later continues based on intent and context
The runtime only clears the rhythm. It does not decide whether the user meant stop, answer first, change direction, or continue afterward. That interpretation belongs to grow-loop, and operator intent outranks remaining backlog availability.
Grow Loop should stop and not call grow_loop when:
- No high-value actionable or preparable work remains.
- Work is complete.
- Remaining work is gated and preparation is complete.
- The checkpoint signature repeats.
- The next step is unsafe, destructive, approval-gated, credential-gated, account-affecting, or externally blocked.
- Validation regresses enough to require a strategy change.
- Recent user intent means stop, answer, change direction, or wait.
Stopping with exact evidence is progress.
- No background worker.
- No hidden task queue.
- No slash-command control surface.
- No cycle budget or goal-session state.
- No Escape/abort ownership; Escape remains baseline Pi behavior for active agent turns.
- No replacement for approval on destructive, publishing, credential, account, or external actions.
Normal continuation:
User: grow loop
Agent: closes one backlog slice, validates, reports evidence, calls grow_loop
Runtime: loop ∞1 → loop 3.0s → while true | grow loop
Terminal stop proof:
Agent: closed release checklist, npm run validate passed, remaining npm publish is approval-gated; restart with "grow loop" after publish approval is ready.
The package uses Pi's source-extension shape: package metadata points directly at index.ts and the bundled skills/ directory. There is no build step or generated dist/ tree.
Repository files:
index.ts— no-argumentgrow_looptool and status scheduler.skills/while-true/SKILL.md— bounded worker-loop protocol with neutral project-local work-surface discovery.skills/grow-loop/SKILL.md— continuation meta-protocol.AGENTS.md— durable project protocol and routing invariants.BACKLOG.md— canonical open work and next growth slices.CHANGELOG.md— completed delivery history and package-version release notes.tsconfig.json— maintainer-side strict no-emit validation for extension and test sources; it is not required by the installed runtime package.