Loop checks and drift#

Agents waste money by repeating themselves and by losing track of their own work. This page covers the loop check, which catches an agent stuck on the same step while it runs, and drift tracking, which catches work an agent redoes, undoes or loses, with commands to see and restore files. It is for developers running long or repeated agent sessions.

Both are plain logic on the machine. Neither makes a model call.

Loop checks#

The loop check is on by default. Agents resend their whole history with each call, so each call shows the agent’s recent steps. A loop is the latest step (a tool call and its result) repeated: the same tool, the same input and the same result, 3 times among the last 8 steps. That covers:

  • the same command failing the same way;

  • the same call getting the same answer, such as an unchanged file read again.

A different result each time is progress, not a loop. The latest step must be one of the repeats, so a loop the agent already left does not count. It reads Anthropic Messages, OpenAI Chat and Responses histories.

What happens#

  • Each loop raises one loop alert per task, for example: Task “fix-login” looks stuck: go test ./... failed 3 times with the same error. It shows in the meter, VS Code and the alert destinations.

  • If someone is watching (the meter, VS Code or the overlay), the call is also held for up to -ask-at-cap with Let it run and Stop (Continue in Slack, Teams, ntfy and on phones).

    • Let it run lets it on.

    • Stop refuses this one call with HTTP 429, code loop_stopped and X-Should-Retry: false, so the agent shows the message instead of retrying. The next call goes through, so you can redirect the agent.

    • No answer lets the call on: a loop is a hint, not a budget.

  • With nobody watching, the alert only.

From a terminal, lockpin approve ID lets a held loop call go on and lockpin deny ID stops it.

Turn it off#

lockpin -loop-check=false

Drift tracking#

In long or repeated sessions an agent rewrites code it already wrote, undoes earlier steps, deletes work, or starts a task an earlier session finished. Each of those steps is paid for. With -drift, Lockpin snapshots your project folder on every model call and checks each step against the history.

Before you begin#

  • git is installed. Your project does not need to be a git repository.

  • Your agent’s calls go through Lockpin.

Turn it on#

  1. Start Lockpin with the project folder:

    lockpin -drift C:\Users\you\projects\myapp
    
    lockpin -drift ~/projects/myapp
    
  2. Optional: write what the work is for, so steps are measured against a goal:

    lockpin goal set -repo C:\Users\you\projects\myapp "Add email login with code verification"
    
  3. Optional, for Claude Code: install the tool-event hook, so findings can tell the agent’s edits from yours:

    lockpin hooks install -agent claude-code -events
    

What is stored#

  • Snapshots go into a separate git repository in your user cache folder (-drift-store changes it). Your project’s own .git, branches and files are never touched.

  • Your .gitignore is respected, and .env, *.pem, *.key and SSH keys are never copied.

  • It sees every change, whether an edit tool, a shell command or you made it.

  • A request with X-Lockpin-Drift: off is left out, for an agent working on another project.

  • It all stays on your machine.

What it flags#

Finding

Example

File deleted and written again

auth.go was deleted at step 4 and written again at step 9. That step cost $0.0120.

File put back to an earlier version

config.go went back to its version from step 3, undoing what steps 5, 7 changed in it.

Function removed and written again

ValidateEmail was removed at step 6 (from user.go) and written again at step 11 in auth.go

Code repeated

12 lines in b.go (lines 40-51) repeat code already in a.go (lines 10-21).

Big rewrite (pivot)

Big change at step 8: 410 lines added and 380 removed (62% of the project)

Changed between sessions

utils.go was deleted while no session was running (found when session 3 started).

Same request as an earlier session

This request looks like the one that started session 2 ...

Plan item ticked with nothing done

With a PLAN.md or TODO.md checklist: "add tests" was checked off ... but no other file changed

A session is one task’s calls with no gap over 30 minutes (-drift-session-gap). Each step’s cost is the task’s spend since its previous step. The spend on steps that got a warning is an estimate: those steps may also have done useful work.

A finding costing at least -alert-drift-usd ($0.50) also raises a drift alert.

See the findings#

lockpin drift -repo C:\Users\you\projects\myapp
lockpin drift -repo C:\Users\you\projects\myapp -all
lockpin drift tree -repo C:\Users\you\projects\myapp

drift lists the latest 20 findings (-all lists every one). The meter’s Drift panel and the VS Code extension show the same.

See or restore a file#

Every finding about a file comes with a command to see or restore the right version:

lockpin show    -repo C:\Users\you\projects\myapp -step 4 auth.go
lockpin restore -repo C:\Users\you\projects\myapp -step 4 auth.go

show prints the file as it was at that step. restore puts it back, and backs up your current copy first.

Against the goal#

Write what the work is for in GOAL.md (or REQUIREMENTS.md), or run lockpin goal set. Without one, the first session’s request is the goal.

  • Optional checkboxes in the file are requirements.

  • A Scope: list of path globs (- web/login/**) says where the work belongs.

lockpin goal                                   # show the goal
lockpin goal set "Fix the login bug without changing the API"
lockpin drift tree

The meter’s “Against the goal” panel and lockpin drift tree show each step with a distance from the goal (0 on goal to 100), work that wandered off drawn as a branch, and steps whose additions are all gone marked as dead branches, with off-goal and thrown-away spend.

Note

The distance is a heuristic from scope, words in the request and file names, and lines still kept. It is not a verdict.

Project notes for the model#

With -drift-brief, Lockpin adds a short note to the model’s instructions at the start of each session: earlier sessions and what they changed, code removed earlier and still missing, recent warnings, and the next plan item. The note stays the same for the whole session, so it stays in the prompt cache. It changes what the model sees, so it is off by default.

Drift options#

Flag

Default

What it does

-drift

off

Project folder to snapshot on every model call.

-drift-store

a folder in your user cache

Where snapshots and the journal are kept.

-drift-goal

GOAL.md or REQUIREMENTS.md if present

Goal file in the project.

-drift-plan

PLAN.md, TODO.md or TASKS.md if present

Checklist file to follow.

-drift-session-gap

30m

Idle time after which a task’s next call starts a new session.

-drift-brief

off

Add project notes to the model’s instructions.

-alert-drift-usd

0.5

Alert on findings costing at least this.

Verify#

  1. Start Lockpin with -drift on a project and let an agent make a few calls.

  2. Run lockpin drift -repo DIR. The session and its steps are listed.

  3. Open the meter’s Drift panel at http://127.0.0.1:8787/lockpin/?view=detailed.

Limits#

  • A reply waits for its snapshot, which runs while the model works, so it only adds delay when snapshotting a large folder takes longer than the model call.

  • Without the agent’s tool-event hook, your edits and the agent’s look the same, and two tasks editing one folder at once share their steps.

  • Functions are found with simple patterns for Go, Python, JavaScript and TypeScript, and Rust. Other languages fall back to matching blocks of six or more identical lines, marked as lower confidence.

  • If snapshots fail, calls go on and drift shows as degraded.

Next steps#