npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@wkqco33/pi-loop-guard

v0.2.0

Published

Pi extension that detects and stops agent loops: repeated tool calls, alternating call cycles, repeated errors, and repeated responses.

Readme

pi-loop-guard

npm license pi-package

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

  1. before_agent_start appends a short "don't loop, report blockers" hint to the system prompt.
  2. tool_call records a digested toolName + stableJson(input) signature and checks for consecutive repeats and repeating cycles.
  3. tool_execution_end tracks consecutive identical failures; any success clears the streak.
  4. message_end compares finalized assistant text.
  5. turn_start and a periodic timer emit soft warnings only.
  6. On a hard stop the run is aborted and the tool call is blocked with { block: true, terminate: true }.
  7. agent_settled and session_shutdown clear 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 observe is 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