pi-no-spin
pi extension that detects when the LLM spins (repeats the same string over and over), interrupts generation, and reminds it to stop
Package details
Install pi-no-spin from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-no-spin- Package
pi-no-spin- Version
1.0.2- Published
- Aug 17, 2026
- Downloads
- 472/mo · 6/wk
- Author
- wilhg
- License
- MIT
- Types
- extension
- Size
- 18 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-no-spin
A pi extension that detects when the LLM spins — repeating the same string over and over — interrupts the generation, and reminds the model to stop — so you don't burn tokens while the model churns out the same segment on repeat.
Why it exists: open-source / self-hosted models (DeepSeek, Qwen, Llama, GLM, …) have a non-negligible chance of falling into output loops — repeating the same sentence, code block, or token sequence continuously without making progress (
deepseek-reasonerand quantized local models are especially prone). pi-no-spin cuts these off in real time.
How it works
- Listen — the extension hooks into pi's
message_updateevent, which fires token-by-token while the assistant streams a response. - Detect — it accumulates the text and runs a periodicity check on the tail: if the last
period × thresholdcharacters satisfytext[i] === text[i + period]for alli(a periodic run), a repeated segment of lengthperiodhas been output at leastthresholdtimes in a row. Period is scanned fromminUnit(default 4) up tomaxUnit(default 300) characters.- Period detection is used instead of block-aligned matching, so it still fires while the model is mid-way through streaming the next repeat (a partial segment) — no false negatives due to alignment jitter.
- Pure-whitespace repetition (indentation / blank lines) is not treated as a loop.
- Repetition of separators (
─and.) is not treated as a loop either — those are visual dividers / dot leaders, e.g. a long─────rule or a.....line, not spinning.
- Interrupt — on detection the extension calls
ctx.abort()to stop generation immediately, shows a ⛔ notification, then queues a follow-up user message telling the model it is stuck in a loop and should re-assess instead of repeating.
Install
pi install git:github.com/wilhg/pi-no-spin
or with SSH shorthand:
pi install git:git@github.com:wilhg/pi-no-spin.git
Then reload in a running pi session:
/reload
Try without installing
pi -e git:github.com/wilhg/pi-no-spin
Usage
Detection is on by default. Configure it with the /nospin command:
/nospin Show status and current configuration
/nospin on|off Enable / disable detection
/nospin threshold N Reps of the same segment that count as a loop (default 7)
/nospin min N Minimum segment length to consider (default 4)
/nospin max N Maximum segment length to consider (default 300)
Examples:
/nospin → pi-no-spin: 🟢 enabled | threshold=7 | minUnit=4 | maxUnit=300 | cooldown=10000ms
/nospin threshold 15 → require 15 consecutive repeats
/nospin max 500 → detect segments up to 500 chars
/nospin off → disable
Configuration is persisted per-session (pi.appendEntry) and restored automatically on the next session_start.
Quick verification
Tell the model something like:
Please repeat the same sentence 20 times in a row.
You should see it interrupted around the 7th repetition — a ⛔ notification appears and the model receives a reminder to stop repeating.
Options & defaults
| Option | Default | Meaning |
|---|---|---|
threshold |
7 | Consecutive reps that count as a loop |
minUnit |
4 | Minimum segment length (chars) |
maxUnit |
300 | Maximum segment length (chars) |
cooldownMs |
10000 | Cooldown between triggers (ms) |
| enabled | true | Detection on by default |
Known limitations
- Non-streaming whole-message arrival: if an entire response arrives at once (non-streaming provider) and the tail of that message happens to contain a few non-repeating closing characters, the tail-anchored periodic window can miss the run. In practice this never matters: with streaming, detection fires at the exact moment the 7th repetition completes — before the model gets a chance to emit any closing text.
- Exact periodicity: the check requires characters at distance
periodto be exactly equal. A model that repeats a segment with slight mutations each time will not trigger (returning the same string byte-for-byte is the common failure mode this targets). - Tool-call loops: repeated identical tool calls are a different loop signature and are not covered (yet).
Development
npm test # runs tests/pi-no-spin.test.mts (Node 22.6+ / 23+, type stripping)
npm test does not require pi or a model — the detection algorithm is pure and unit-tested.
License
MIT © wilhg