@wkqco33/pi-loop-guard
Pi extension that detects and stops agent loops: repeated tool calls, alternating call cycles, repeated errors, and repeated responses.
Package details
Install @wkqco33/pi-loop-guard from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@wkqco33/pi-loop-guard- Package
@wkqco33/pi-loop-guard- Version
0.2.0- Published
- Sep 12, 2026
- Downloads
- 284/mo · 284/wk
- Author
- wkqco33
- License
- MIT
- Types
- extension
- Size
- 50.3 KB
- Dependencies
- 0 dependencies · 1 peer
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-guard
A pi extension that detects runaway agent loops and stops them before they burn tokens.
It watches the behaviour a model actually exposes — tool calls, tool errors, and final assistant responses — and breaks the loop when a repeat pattern appears. Long but productive runs are never interrupted.
Install
pi install npm:@wkqco33/pi-loop-guard
Try it without installing:
pi -e npm:@wkqco33/pi-loop-guard
Reload a running pi session with /reload, or restart pi.
What it detects
| Signal | Pattern | Default | Action |
|---|---|---|---|
| Repeated tool call | A A A |
3 in a row | block + abort |
| Repeating tool cycle | A B A B A B, A B C A B C … |
3 full cycles (cycle length ≤ 3) | block + abort |
| Window tool frequency | A … A … A … A (interleaved) |
4 in 10-call window | block + abort |
| Repeated tool error | same error 3× in a row | 3 in a row | abort |
| Repeated assistant response | identical text 3× in a row | 3 in a row | abort |
| Turn count | > 12 turns in a run | 12 | warn only |
| Elapsed time | > 180 s in a run | 180 s | warn only |
Tool calls are compared by tool name and a deterministic serialization of the
arguments, so read(a.ts) and read(b.ts) are different calls.
Error keys are normalized (digits collapsed, UUIDs, timestamps, and hex pointers masked), so dynamic tokens share a key.
Turn count and elapsed time are deliberately soft: a long run that keeps making progress is allowed to finish. Only genuine repeat patterns hard-stop.
Modes
| Mode | Behaviour |
|---|---|
on (default) |
Report and hard-stop loops |
observe |
Report loops but never block or abort — use this first on a new machine |
off |
Disabled entirely, including the system-prompt hint |
Start with observe for a few days, then switch to on once you trust the
signal on your workloads.
Commands
/loop-guard show current status
/loop-guard status same as above
/loop-guard inspect show recent tool call history
/loop-guard on enable blocking
/loop-guard off disable
/loop-guard observe report only, never block
/loop-guard reset reset the current run's counters and tripped flag
Configuration
Config file
Create .pi/loop-guard.json in your project (or ~/.pi/loop-guard.json globally).
Project settings override global settings.
{
"mode": "on",
"locale": "en",
"maxTurns": 12,
"turnTimeoutMs": 180000,
"repeatToolThreshold": 3,
"repeatErrorThreshold": 3,
"repeatAssistantThreshold": 3,
"cycleRepeats": 3,
"maxCycleLength": 3,
"repeatFrequencyThreshold": 4,
"frequencyWindowSize": 10,
"ignoreTools": ["sleep"],
"toolThresholdOverrides": { "bash": 2 }
}
"enabled": false is accepted as an alias for "mode": "off".
Environment variables
Environment variables override the config file.
export PI_LOOP_GUARD_MODE=on # on | off | observe
export PI_LOOP_GUARD_LOCALE=en # en | ko
export PI_LOOP_GUARD_MAX_TURNS=12
export PI_LOOP_GUARD_TURN_TIMEOUT_MS=180000
export PI_LOOP_GUARD_REPEAT_TOOL=3
export PI_LOOP_GUARD_REPEAT_ERROR=3
export PI_LOOP_GUARD_REPEAT_ASSISTANT=3
export PI_LOOP_GUARD_CYCLE_REPEATS=3
export PI_LOOP_GUARD_MAX_CYCLE_LENGTH=3
export PI_LOOP_GUARD_REPEAT_FREQUENCY=4
export PI_LOOP_GUARD_FREQUENCY_WINDOW=10
export PI_LOOP_GUARD_IGNORE_TOOLS=sleep,wait
export PI_LOOP_GUARD_TOOL_OVERRIDES="bash=2,read=5"
A stricter setup:
export PI_LOOP_GUARD_REPEAT_TOOL=2
export PI_LOOP_GUARD_REPEAT_ERROR=2
export PI_LOOP_GUARD_REPEAT_ASSISTANT=2
Precedence
built-in defaults < config file < environment variables < /loop-guard command
How it works
before_agent_startappends a short "don't loop, report blockers" hint to the system prompt.tool_callrecords a digestedtoolName + stableJson(input)signature and checks for consecutive repeats and repeating cycles.tool_execution_endtracks consecutive identical failures; any success clears the streak.message_endcompares finalized assistant text.turn_startand a periodic timer emit soft warnings only.- On a hard stop the run is aborted and the tool call is blocked with
{ block: true, terminate: true }. agent_settledandsession_shutdownclear timers and counters.
The detector itself (src/detector.ts) is pure and has no pi dependency, which is
why it is exhaustively unit-tested.
Safety
- Runs with the same privileges as the pi process.
- Never writes session content or API keys to disk or to logs.
- Only counts and hashes in memory; nothing is persisted.
- Hard-stops can interrupt a legitimate retry, so
observeis the recommended starting mode. - Turn/time limits never stop a run on their own.
Development
npm install
npm run verify # typecheck + format:check + tests
npm run coverage # 100% line coverage on src/
npm run bench # hot-path micro-benchmarks
npm run pack:check
Tests use the Node.js built-in test runner with native TypeScript type-stripping — no test framework dependency. Contributors and agents must follow AGENTS.md.
License
MIT © wkqco33