pi-loop-mode 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robert Ressl
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # pi-loop-mode
2
+
3
+ > Unattended loop mode for [pi](https://github.com/earendil-works/pi) — endless, self-correcting agent iterations for multi-day runs.
4
+ >
5
+ > **Ausführliche Dokumentation mit Beispielen (deutsch): [DOCUMENTATION.md](DOCUMENTATION.md)**
6
+
7
+ Pi package for an unattended loop mode: give the agent a goal and it works on it in small iterations until **you** stop it — designed for multi-day runs where a product keeps growing (features, tests, bug fixes, refactoring, docs). Works with commercial and open-source models alike.
8
+
9
+ ## What it does
10
+
11
+ - **Endless by default**: no iteration cap. The loop runs until `/loop stop`. Set `--max N` for an optional cap, `--until-done` if completion should actually stop the loop.
12
+ - **Objective goal function** (`--check "CMD"`): a shell command run after every iteration. Exit code 0 = criteria met (verified completion in `--until-done` mode — the check decides, not the model's claim). Optional `SCORE: <n>` output enables progress tracking: score improvements count as real progress, score regressions trigger an immediate "find and fix the regression" prompt. Essential against models that claim success without delivering.
13
+ - **Error resilience**: model/provider errors (crashes, timeouts, rate limits, empty responses) never end the loop. It retries with exponential backoff (5s → 5min) and tells the model to re-establish its bearings and continue.
14
+ - **Garbage/repetition detection**: repeated assistant answers (exact fingerprints *and* near-duplicates via trigram similarity with numbers masked, alternating A-B-A-B patterns), repeated tool results/errors, repeated questions, and narration-only turns (3 turns without a single tool call) are all detected. Instead of pausing, the loop injects rotating recovery strategies (switch subtask, write PROGRESS.md, run tests and fix one failure, review diffs, list alternative approaches) with escalating delays — important for weaker open-source models that loop on the same output.
15
+ - **Degenerate-generation kill switch**: if one sentence dominates a single response ("Let me continue with improvements. …" × 40), the stream is aborted live (≥ 6 repeats), the stored message is truncated after the first repetition, and already-poisoned context is sanitized before every LLM call — so the garbage can never reinforce itself.
16
+ - **Escalation ladder on persistent stuck**: rotating strategy → anti-repetition sampling penalties (`frequency_penalty`/`presence_penalty` + higher temperature for 3 turns, OpenAI-compatible APIs only) → hard reset with banned openings → one rescue turn by a stronger model (`--rescue-model M`, after 3 consecutive stuck interventions) → automatic context compaction (after 5).
17
+ - **Backlog-driven improvement mode**: after `LOOP_DONE` in endless mode the loop works off an `IMPROVEMENTS.md` backlog — concrete checklist items with file paths and acceptance criteria; vague items ("add support for other platforms") are forbidden.
18
+ - **Per-iteration JSONL log** (`.pi-loop-log.jsonl`) with `/loop stats`: event distribution, interventions, productive iterations/hour, score trend — compare models and goal phrasings across runs.
19
+ - **No-progress audit**: if no concrete file/system change happens for 8 iterations, the loop demands a tangible artifact (file change, passing test, fixed bug).
20
+ - **Never waits for a human**: `LOOP_BLOCKED:` does not pause the loop. The model is told to make a documented assumption (`ASSUMPTIONS.md`) and keep going.
21
+ - **Done ≠ stop (endless mode)**: when the model reports `LOOP_DONE:`, the loop continues with improvement work — new features, more tests, bug fixes, refactoring, performance, docs.
22
+ - **Auto-resume**: loop state is persisted in the session; after a pi restart/reload an active loop resumes automatically after 3 seconds.
23
+ - **Short iterations**: every loop prompt tells the model to do one concrete progress batch and keep output under 1,200 characters, so context stays small and normal compaction works.
24
+ - **Operator control**: `Esc` (abort) pauses the loop; `/loop resume` continues it; `/loop stop` stops it; `/loop end` clears state.
25
+
26
+ ## Recommended workflow: separate goal, preparation, and execution
27
+
28
+ ```text
29
+ /loop goal <goal + flags> # 1. set the goal — starts nothing
30
+ /loop prepare --model anthropic/claude-opus-4-6 # 2. strong model writes GOAL.md + check script (ends with GOAL_READY:)
31
+ /loop run --model vllm-omega/qwen3-coder-30b --rescue-model anthropic/claude-sonnet-4-5
32
+ # # 3. cheap/local model works the loop against the spec;
33
+ # # the rescue model takes over for one cleanup turn when stuck
34
+ ```
35
+
36
+ Planning and execution are decoupled: an expensive model writes a precise spec once (`GOAL.md`, reviewable/editable before the run), a cheap or local model executes it for days. The run model is persisted and restored on auto-resume. Switch models mid-run with `/loop stop` + `/loop resume --model M`.
37
+
38
+ ## Commands
39
+
40
+ Pi slash commands only match the first word, so this package registers a single `/loop` command with subcommands:
41
+
42
+ | Command | Description |
43
+ |---------|-------------|
44
+ | `/loop goal <goal> [flags]` | Set goal + config without starting. `/loop goal` shows it. |
45
+ | `/loop prepare [--model M] [--file F]` | Have a (strong) model write the goal spec (`GOAL.md`) + check script. |
46
+ | `/loop run [--model M]` | Start the loop, optionally with a different model. |
47
+ | `/loop start <goal>` | Shortcut: goal + run in one step (endless loop). |
48
+ | `/loop start <goal. Done when: criteria>` | Optional explicit completion criteria. |
49
+ | `/loop start <goal> --max 50` | Optional iteration cap (pauses at N). |
50
+ | `/loop start <goal> --delay 30` | Wait 30s between iterations. |
51
+ | `/loop start <goal> --check "npm test"` | Objective goal check after every iteration. |
52
+ | `/loop start <goal> --check "./check.sh" --check-timeout 300` | Check with custom timeout (default 120s). |
53
+ | `/loop start <goal> --until-done` | Stop on verified completion (check passes; without check: `LOOP_DONE:`). |
54
+ | `/loop start <goal> --rescue-model M` | Stronger model takes over for one cleanup turn after 3 consecutive stuck interventions. |
55
+ | `/loop resume [--max N] [--model M] [--rescue-model M]` | Continue a stopped/paused loop, optionally switching models. |
56
+ | `/loop status` | Show loop state, errors, interventions, iterations. |
57
+ | `/loop stats` | Summarize the per-iteration JSONL log: events, interventions, iterations/hour, score trend. |
58
+ | `/loop stop` | Stop the loop and preserve state. |
59
+ | `/loop end` | End the loop and clear state. |
60
+ | `/loop help` | Show command help. |
61
+
62
+ Example — a 5-day product-building run:
63
+
64
+ ```text
65
+ /loop start Build a complete REST API for task management in ./taskapi: CRUD, auth, SQLite, tests, docs. Keep improving it: more features, better tests, bug fixes, refactoring.
66
+ ```
67
+
68
+ Then stop it whenever you want with `/loop stop`.
69
+
70
+ Example — with objective goal function:
71
+
72
+ ```text
73
+ /loop start Build a REST API in ./taskapi. Done when: all tests pass --check "cd taskapi && npm test" --until-done
74
+ ```
75
+
76
+ ### Writing a goal check script
77
+
78
+ The check command is the loop's fitness function. Exit 0 = done criteria met; print `SCORE: <n>` (higher = better) for progress/regression tracking:
79
+
80
+ ```bash
81
+ #!/usr/bin/env bash
82
+ # check.sh — example goal function
83
+ cd taskapi || { echo "SCORE: 0"; exit 1; }
84
+ npm run build >/dev/null 2>&1 || { echo "SCORE: 0"; exit 1; } # build must work
85
+ passed=$(npm test 2>/dev/null | grep -oE '[0-9]+ passing' | grep -oE '[0-9]+' || echo 0)
86
+ echo "SCORE: $passed"
87
+ [ "$passed" -ge 50 ] && exit 0 || exit 1 # done when 50+ tests pass
88
+ ```
89
+
90
+ Score ideas: number of passing tests, test coverage, implemented endpoints, `-` lint warning count. The score appears in every loop prompt and in the status bar, and drives regression detection.
91
+
92
+ ## How failures are handled
93
+
94
+ | Situation | Behavior |
95
+ |-----------|----------|
96
+ | Model/provider error (crash, rate limit, timeout) | Retry with exponential backoff, then "recover" prompt; never gives up. |
97
+ | Model repeats the same answer/tool call/question | Stuck intervention with rotating strategies and escalating delay. |
98
+ | Model repeats a *near*-identical answer (≥ 80 % trigram similarity, numbers masked) | Also a stuck intervention. |
99
+ | Model answers with narration only (3 turns without any tool call) | Also a stuck intervention. |
100
+ | One sentence repeated many times within a single response | Stream aborted mid-generation (≥ 6 repeats); stored message truncated; context sanitized before every LLM call. |
101
+ | 3 consecutive stuck interventions | Hard reset (banned openings, turn must start with a tool call) — or a one-turn takeover by the `--rescue-model`, if configured. |
102
+ | 5 consecutive stuck interventions | Automatic context compaction (repetitive filler explicitly excluded from the summary). |
103
+ | Any stuck intervention | Additionally: anti-repetition sampling penalties for the next 3 turns (OpenAI-compatible APIs). |
104
+ | Model produces analysis but no changes for 8 iterations | Audit prompt demanding a tangible artifact. |
105
+ | Model says `LOOP_DONE:` (endless mode) | Loop continues with backlog-driven improvement work (`IMPROVEMENTS.md`). |
106
+ | Model says `LOOP_DONE:` but goal check fails (`--until-done`) | Loop rejects the claim and demands fixing what the check reports. |
107
+ | Goal check score drops | Immediate regression prompt: inspect diffs, fix what broke. |
108
+ | Goal check passes (`--until-done`) | Verified completion — loop stops. |
109
+ | Goal check command itself fails to run | Warning shown; loop continues without blocking. |
110
+ | Model says `LOOP_BLOCKED:` | Loop instructs it to assume, document in ASSUMPTIONS.md, and continue. |
111
+ | Operator presses Esc | Loop pauses; `/loop resume` continues. |
112
+ | pi restart / reload | Active loop auto-resumes after 3s, restoring the stored loop model. |
113
+ | Loop model unavailable after restart | Warning; loop continues with the current model. |
114
+ | `--max N` reached | Loop pauses; `/loop resume` continues (uncapped if exhausted). |
115
+
116
+ ## Install
117
+
118
+ ```bash
119
+ pi install npm:pi-loop-mode
120
+ ```
121
+
122
+ Or from a local checkout:
123
+
124
+ ```bash
125
+ pi install /path/to/pi-loop-mode
126
+ ```
127
+
128
+ Then start or reload pi and run `/loop help`.
129
+
130
+ > **Security note:** pi packages run with full system access, and this package is built for *unattended* operation — the model works for hours without supervision. Use a dedicated directory/repo, ideally a VM or container, and keep production systems out of reach.
131
+
132
+ ## Files
133
+
134
+ ```text
135
+ pi-loop-mode/
136
+ ├── package.json
137
+ ├── README.md # This file
138
+ ├── DOCUMENTATION.md # Full documentation with examples (German)
139
+ ├── CHANGELOG.md
140
+ ├── LICENSE # MIT
141
+ ├── extensions/index.ts # The loop extension (all logic)
142
+ ├── skills/loop-skill/SKILL.md # Behavior rules for the model in loop mode
143
+ └── prompts/loop-prompt.md # Prompt template
144
+ ```
145
+
146
+ ## Notes
147
+
148
+ - Loop state is persisted with `pi.appendEntry()` and does not add large payloads to model context.
149
+ - The loop deliberately allows Pi's normal compaction behavior; short per-turn output keeps multi-day runs compactable.
150
+ - Recommended for long runs: work in a git repo so the model can commit incrementally, and tell it so in the goal.
151
+ - The per-iteration log `.pi-loop-log.jsonl` is written to the working directory — add it to `.gitignore` if you don't want it committed.
152
+ - "Continue" prompts are slightly varied per iteration; identical prompts encourage identical (repetitive) answers from weaker models.