Glossary · agent replay

Agent drift

▸ Definition

Agent drift is the unplanned change in an AI agent's behavior across runs of the same job: the instructions stay the same, but the agent's routing, tool use, or output diverges from the workflow it was trusted to run — pushed by model updates, shifting context, accumulated memory, or a world that changed under the agent's assumptions. Tool-call drift (tool-use drift in some taxonomies) is the subtype visible at the tool-call layer: which tools the agent invokes, with what arguments, in what order, and with what outcomes, compared against a known-good baseline. Because tool calls are typed JSON requests and responses, tool-call drift is the one form of drift that can be detected mechanically — by recording a working run and diffing later runs against it — rather than by judging transcripts.

One name, several failure modes

The term arrived with agents in production, and it names an observation every operator makes eventually: an agent given the same job does not do the same job. The model version changes under the prompt. Retrieved context shifts. Accumulated memory nudges the plan. The agent improvises around a transient error and the improvisation sticks. No single step is wrong, and each looks like a reasonable fix in isolation — but the fixes compound into a workflow nobody reviewed.

Because the term is young, the taxonomies disagree at the edges. A production-monitoring treatment splits drift by cause: goal drift, context drift, reasoning drift, and collaboration drift — the last covering the agent's integrations with tools and other agents. A security glossary centers the workflow instead, defining agent drift as change in an agent's behavior, routing, or tool use that departs from the authorized plan. An academic study of multi-agent systems frames it as progressive behavioral degradation over extended interactions, with tool-usage patterns among its measured signals. The common thread across all three: drift is divergence from an intended baseline. Which exposes the practical problem — most agent behavior has no recorded baseline to diverge from.

Tool-call drift: the subtype you can measure

Reasoning is hard to compare across runs; tool calls are data. Everything an agent does to the world outside its context window passes through them — a typed JSON request, a typed JSON response, a success or a failure. That layer can be recorded once and compared mechanically forever, which is why tool-call drift is the subtype worth building detection around: it is the part of agent drift with an objective before-and-after.

What counts as drift at that layer, concretely: a step's outcome changed (a step that passed now fails), the workflow's shape moved (a step was added or removed), or a step that used to run clean needed help to pass. What never counts: timing, and fresh data. Same steps, fresh values is not drift — it is the workflow working. A replayed report whose download count moved since last week has not drifted; a step whose response stopped matching its schema assertion has. Structure and outcomes, never data.

Reelier's diff splits the verdict further into hard and soft. Hard drift is an outcome or structure change — the run did something different. Soft drift is the same outcome reached at a different escalation level: the step still passed, but only because a model healed a stale expectation, which means the world moved underneath it. A strict CI gate can fail on both; a lenient one on hard drift only.

Detection: record a baseline, diff every run after

Detection needs a baseline, so the loop starts by recording one. Capture a working run's tool calls — on Claude Code, reelier scan reads the transcript history in ~/.claude/projects; Cursor keeps its history in a SQLite database, so there is no history scan for it and capture is the reelier mcp --wrap recording proxy instead. Compile the recording into a SKILL.md with an assertion on every checkable step, then replay it with reelier run: deterministic, 0 LLM tokens at the default level, and read-only — recorded write steps do not re-fire without --allow-writes.

From the second run on, reelier diff <skill> compares the last two runs in .reelier/runs/<skill>.jsonl and prints a per-step verdict: SAME or DRIFTED, with the failing assertion as the why, exit code 1 on drift. That exit code is the product. Put replay-then-diff on the schedule and drift stops being a vibe — it is a red job naming the step that moved, instead of an agent quietly adapting around a change nobody approved.

The same mechanism catches drift from both directions. World drift: the workflow is frozen, upstream changes shape, an assertion fails loudly on replay. Agent drift proper: a new model ships — re-record the job on it and diff the fresh record against the frozen baseline, and steps added, removed, or flipped show exactly how the new model's behavior moved before it reaches production. When escalation is enabled (opt-in and BYOK: L1 re-evaluates the already-captured observation, L2 may re-execute a single read or idempotent-write step, destructive steps never escalate), the model still never edits the skill file — it proposes a narrow, validated patch, and the healing shows up in the next diff as soft drift rather than silence.

What a diff cannot see

A tool-call diff sees the tool-call layer, full stop. Reasoning drift that produces identical tool calls is invisible to it, and the prose an agent writes or the judgment it exercises between calls is out of scope — evaluating those takes a model, and Reelier does not pretend otherwise. Detection is also only as good as capture: a gate built on a reconstructed history can miss what the reconstruction missed, which is why the wrap proxy — the lossless recording — is the higher-fidelity source than a scan.

And a replay-based gate guards a recorded workflow; it does not monitor an agent free-running in production. It answers a narrower question — did this known-good job still run the same — and answers it with an exit code. For the drift modes outside that boundary, the honest tools are evals and observability, not replay.

A real receipt

The receipt below is a real drift detection, deliberately provoked — the provenance spells out exactly how. A scratch copy of the registry-latest portfolio skill had its version assertion pinned to a stale /^0\.11\./ — the precise anti-pattern the shipped skill's own comments warn against — after a first replay had passed. The live npm registry answered 0.13.0, the step failed, and reelier diff turned the divergence into a per-step verdict and exit code 1.

Reelier · replay receipt
$ npx -y reelier@latest run registry-latest.skill.md
✗ Step 1 — Latest dist-tag from the registry [failed] 159ms
    - json.version matches /^0\.11\./ failed: got "0.13.0"

FAILED: 0/1 steps ok, 1 failed, 159ms total

$ npx -y reelier@latest diff registry-latest
  ✗ Step 1 "Latest dist-tag from the registry": passed → failed — json.version matches /^0\.11\./ failed: got "0.13.0".

⚠ DRIFTED — 1 outcome/structure change(s): #1 outcome-changed.
verbatim output

Induced-drift demonstration, actually run on 2026-07-21 with the published CLI (npx -y reelier@latest, resolved to reelier@0.13.0) in a scratch directory, against a copy of examples/portfolio/registry-latest.skill.md from the seldonframe/reelier repo. The baseline replay passed (1/1 steps, 159ms); pinning the version assertion to /^0\.11\./ was the only edit between the two runs. Verbatim output, nothing mocked.

FAQ

Is fresh data drift?

No. The diff compares structure, outcomes, and escalation level — never bound values. A replayed report whose numbers moved since last run is the workflow working; a step whose assertion started failing is drift. That is also why skill assertions are patterns and types rather than pinned values: ^\d+\. holds for every release that will ever ship, while the pinned ^0\.11\. in this page's demonstration was already stale by the time of the demonstration (the registry answered 0.13.0).

Does a model upgrade count as agent drift?

It is one of the loudest sources of it — new model, same prompt, different tool-call behavior. The replay itself is pinned and model-free, so an upgrade cannot move it. To measure what the upgrade changed, re-record the job on the new model and reelier diff the fresh record against the frozen baseline: SAME or DRIFTED, per step, before the new model takes over the schedule.

Reading as an agent? This page has a markdown twin: /learn/tool-call-drift/md