Coding-Agent State Protocol

State Drift: Why AI Coding Agents Lose Track of Your Project — and the Deterministic Fix

Across many agents, sessions and models, the state you recorded quietly diverges from what git actually contains. That gap has a name, a cost, and a mechanical fix.

11 July 2026 · 7 min read · deterministic verification

You are ten sessions into a project. A file says the last shipped commit is a1b2c3d and the current phase is "auth, in review." Git says the last commit is f9e8d7c and the branch is three merges past that phase. Nobody lied. The record simply fell behind reality, one session at a time, and no step in the loop ever compared the two.

That gap between your recorded state and your real state in git is state drift. It is the quiet failure mode of AI-assisted development, and it gets worse precisely as the work gets more autonomous — more agents, more sessions, more models, each trusting a status file that nothing validates.

Diagram: the model (fuzzy, probabilistic context) on the left, git (sharp-edged, the record) on the right, and casp check as the deterministic gate between them, exiting PASS or FAIL.
The deterministic floor: state versus git, decided by an exit code, not a model.

What state drift actually looks like

State drift is undramatic, which is why it survives. A concrete instance:

# the recorded state
state.json  →  last_commit: a1b2c3d   phase: "auth · in review"
# what git actually holds
git HEAD    →  f9e8d7c            (auth merged, billing started)

✗ the file and the repository disagree — and nothing noticed.

The next agent opens the project, reads the file, and orients itself against a world that no longer exists. It "resumes" a review that already merged. Multiply that across a fleet of agents or a week of sessions and the record becomes fiction — confidently, in prose a model wrote and no check ever tested.

Why it happens: the state is prose, and prose isn't verified

Coding agents are good at editing code and good at writing plausible summaries of what they did. The summary — the phase, the "next step," the last commit — is generated text. It is written with the same probabilistic process that writes the code, and it is subject to the same failure: it can be confidently wrong. When the only record of "where we are" is a paragraph a model produced, the record inherits the model's uncertainty.

Git, by contrast, is not prose. It is a deterministic ledger with an exact answer to "what is actually here." The drift is the distance between the two, and it accumulates because nothing in the normal loop compares the paragraph to the ledger.

Why storage-and-recall tools don't close the gap

The reflex is to reach for a "memory" layer — something that stores context and hands it back next session. That helps a model re-load what it was told, but it does not verify it. A store-and-recall system will faithfully hand back the same drifted paragraph it was given; if the record was wrong when it was saved, it is wrong when it is recalled, now with a veneer of persistence.

The distinction is categorical, and it's the whole point: storage answers "what did we say?" Validation answers "is it true?" Drift is a truth problem, not a recall problem — so the fix has to be a check, not a cache.

And the check cannot itself be a model. If a probabilistic system verifies a probabilistic record, you have added a second opinion, not a ground truth. The one thing in the loop that must not be a model forming an opinion is the thing that decides whether the state is true.

The fix: validate state against git, deterministically, at the boundary

This is exactly the job of CASP — the Coding-Agent State Protocol, and it is deliberately narrow. CASP does one thing: it proves your project's recorded state matches git, with a hard exit code, and it blocks the push the moment they disagree.

$ casp check
PASS  state.json last_commit matches HEAD
PASS  next_prompt exists and is queued
PASS  last_session_id maps to a session log
──────────────────────────────
casp:check · 3 PASS · 0 WARN · 0 FAIL   (exit 0)

# after drift:
FAIL  last_commit a1b2c3d is not at HEAD (f9e8d7c)
casp:check · 2 PASS · 0 WARN · 1 FAIL   (exit 1 — push blocked)

No model runs inside that check. It is state versus git, and its answer is an exit code: 0 clean or 1 drift. That is the deterministic floor of the self-verification loop — the one gate that isn't the model grading its own homework.

State-machine diagram: casp next, agent works, casp check, git push — with a PASS path continuing to push and a FAIL path looping back to the agent, both the start and the push marked as gated boundaries.
Both boundaries gated: the floor fires inside the loop, not beside it.

Both boundaries, gated

Drift is cheapest to catch where it would escape. CASP gates two boundaries:

What CASP is not

Its usefulness comes from its boundaries. CASP does not orchestrate agents, schedule work, review code, or manage tasks, and no LLM — not even advisory — ever enters the check. It is git-native, local-only, zero telemetry, and model-agnostic: it works the same with today's coding agents and whatever ships next, because it never depended on any of them. It is a floor, not a harness.

Start in two minutes

# install
npm i -g @justethales/casp

# in your repo
casp init            # seed the state files
casp check           # prove state == git (exit 0/1)
casp install-hook    # gate every push on drift

@justethales/casp · MIT · git-native · zero telemetry · source on GitHub

The model holds the context. CASP proves the state is true — against git.

Related articles