Skip to content

Drift Detector

Claude Code + Grok drift detection plugin — scores every assistant turn against your output contract and steers the LLM back when instruction-following erodes.

plugin-validate License: FSL-1.1-ALv2 Docs Claude Code plugin

Drift Detector scores every assistant turn for how far it has wandered from the contract you set — a terse persona, hard length/format rules, an in-character voice — and quietly steers it back. A status-line badge shows live drift. The next prompt gets a one-shot correction nudge only when the previous reply broke contract. Deterministic, dependency-free, never touches session reliability.

Install

Claude Code

/plugin marketplace add 88plug/claude-code-plugins
/plugin install drift-detector@88plug

Grok Build

grok plugin marketplace add 88plug/claude-code-plugins
grok plugin install drift-detector@88plug --trust

Then wire the status-line badge (the one piece a plugin manifest cannot auto-install):

bash "$(/plugin path drift-detector)/install.sh"

install.sh is idempotent. It merges the badge into ~/.claude/settings.json, composes with any existing statusline, and writes a timestamped backup.

Tip

Hooks, commands, skills, and the MCP server wire automatically from the plugin manifest. Only the statusline needs the install script.

Quickstart

Set a contract, work a few turns, then check drift:

> from now on answer in caveman style: terse, no preamble, no hedging
> /drift-detector:status

You should see something like caveman | 12% | ok. When a reply relapses into hedging or verbosity, the badge flips to DRIFT 98% and the next prompt is quietly reminded to tighten up.

Note

F1=0.9973 on 1,283 real-corpus entries (fp=0, tp=375, fn=2, tn=906). 190-session synthetic eval: 100% accuracy, FP=0. Adversarial suite included. The FP=0 constraint held across all 21 tuning rounds.

Statusline badge

After install.sh, the Claude Code statusline shows a live drift segment:

Badge Meaning
fit 12% On contract (green)
drift 55% Warn band — near threshold (yellow)
DRIFT 98%↑ Above threshold; arrow is trajectory (red)

Trajectory arrows: rising, recovering, stable. Clean sessions suppress the arrow. A dialogic segment (fit/eng) may append when present.

The badge is a single file read of ~/.claude/.drift-state — no Python, no DB on the hot path. Uninstall with:

bash "$(/plugin path drift-detector)/install.sh" --uninstall

Profiles

A profile is the output contract plus how to score deviation: threshold, sensitivity, per-class weights, and verbosity/length calibration.

Profile Threshold Use case
caveman 50 Terse persona, no preamble, no hedging
strict-instructions 60 Strict rule-following, low filler
persona 65 In-character voice work
strict 55 Maximum sensitivity
relaxed 75 Only extreme drift flagged
/drift-detector:profile list
/drift-detector:profile caveman
/drift-detector:profile show

Ship your own as JSON under $CLAUDE_PLUGIN_DATA/profiles/ and switch with /drift-detector:profile <name>. Full schema and authoring guide: Profiles.

MCP tools

The plugin registers a read-mostly MCP server (drift-detector). The model can call these without slash commands:

Tool What it does
drift_status Current rollup: score, verdict, turn count, drift rate, EWMA, active profile
drift_recent Last N scored turns (ts, score, verdict, profile)
drift_explain Score arbitrary text against a profile; returns offenders + component breakdown
drift_list_profiles Installed profiles and which is active
drift_set_profile Activate a profile by name (writes active-profile file only)

All query tools open the SQLite index read-only. drift_set_profile never touches the DB.

Commands

Command What it does
/drift-detector:status Live score, verdict, drift rate, trend
/drift-detector:report Per-turn history and dominant offenders
/drift-detector:profile Switch or inspect (name, list, show)
/drift-detector:reset Clear live state (session or all)
/drift-detector:debug Toggle structured hook logging (on / off)

Features

Feature What it does
Per-turn scoring Deterministic 0–100 drift score on every Stop
Live badge Status-line segment; composes with your existing statusline
One-shot nudge Correction only when drifted — never nags
Profiles Bundled contracts plus your own JSON
Morin trajectory Adaptive vs degenerative, velocity, chronic subclinical
Repeating-spike detection Catches relapsing alternating patterns
DCD pipeline Deferred Correction Detection: scans N+1…N+10 for delayed feedback
Rule + DCD scoring Stop-hook runtime: rule engine + drift-control detector (ExtraTree is eval-only)
MCP tools Five tools for status, history, explain, profiles
Commands status, report, profile, reset, debug, calibrate

How it works

SessionStart initializes writable state. Stop scores the last assistant turn (src/lib/drift_score.py), persists to a WAL-mode SQLite index, writes the badge, and drops a marker if the turn drifted. UserPromptSubmit consumes that marker and injects a correction only when drift is degenerative.

The scoring engine is pure stdlib: no network, no third-party deps. Same text and profile always produce the same score. Full pipeline (point engine, trajectory, eval-only ExtraTree + DCD): Algorithm.

Metrics

Tuned through 21 scientific-method rounds on a 1,283-entry real corpus:

Round F1 Notes
R0 0.21 Baseline
R18 0.633 22-feature LR classifier
R19 0.9543 ExtraTree 43-feature + DCD steps=8
R20 0.977 11 new classify_user_reply patterns + DCD steps=10
R21 0.9973 17 patterns + exact-match gate + URL gate

Two irreducible FNs remain (credential provision in ok context; bare "Try now"). Precision = 1.000 (fp=0). Full campaign: Eval & Tuning.

Development

make selftest    # engine self-test
make test        # pytest suite
make validate    # full plugin CI gate
bash scripts/run-python.sh scripts/adversarial_classify_test.py   # 37-case adversarial unit test

License

FSL-1.1-ALv2 © 2026 88plug