Skip to content

Repository files navigation

driftcheck banner

driftcheck

CI License: MIT Python 3.9+ Dependencies Tests

The cross-layer updater for your agent arsenal. Skills, MCP servers, and plugins — one drift picture, one update path, one command to undo any of it.

$ driftcheck check
SKILLS   104 scanned  (adopted 1, git 2, orphans 101)
  [adopted] grilling          up to date
  [git]     lieflat-charts    9 behind   <- UPDATE
  [orphan]  101 skills with no provenance
MCP       floating 7 · outdated 0 · current 0        <- PIN
PLUGINS   marketplaces refreshed 46d ago             <- REFRESH
SUMMARY   drift items: 10
resolve:  driftcheck update          undo:  driftcheck restore latest

Why this exists

Every manager owns one layer and pretends the others don't exist:

Tool Skills MCPs Plugins Orphan provenance Rollback
skills.sh / gh skill ✅ — — ❌ (creates orphans) —
Smithery / mcpm — ✅ — — —
claude plugin update — — ✅ — —
driftcheck ✅ ✅ ✅ ✅ adopt ✅ snapshots

Most real setups have drift in all three layers at once — and copy-installed skills with no origin, so they can never be updated or audited. driftcheck is the one tool that sees the whole picture and never leaves you stranded.

The never-breaks contract

  1. Reporters never touch your state. check is fully read-only (it does not even git fetch: git skills are reported against already-local refs, honestly labelled). inventory writes only driftcheck's own state file.
  2. Mutators default to dry-run. update, pin, and adopt show a plan first; --write is the explicit gate.
  3. One batch, one snapshot, no exceptions. Every mutation batch snapshots every file, directory, and lock it may touch — before touching anything, including files the batch will create. If the snapshot fails, the batch aborts with nothing changed.
  4. One command undoes the whole batch. driftcheck restore latest — or any past snapshot. Restore also deletes files the batch created, so "undo" really means back to before, not mostly back.

Install & run

Python 3.9+, standard library only — zero dependencies, zero supply-chain surface.

git clone https://github.com/kinti/driftcheck.git && cd driftcheck
./driftcheck check          # or: uvx --from . driftcheck check (once packaged)

Publishing to PyPI (uvx --from driftcheck driftcheck) is pending; run from a checkout until then.

Commands

Command Type What it does
check reporter Full three-layer drift report, fully read-only. Exit 1 when drift exists (cron-friendly). --json available.
inventory reporter* Scan skill dirs, classify each (adopted / git-remote / git-local / orphan), write driftcheck's own state file. *Touches nothing outside ~/.config/driftcheck/.
adopt <skill> <owner/repo> --subpath <p> [--write] mutator Give an orphan skill provenance (git clones are rejected). Records the upstream HEAD at adoption time — not the historical install commit, which is unknowable; the first refresh after adoption may therefore bring changes older than your copy. Lock write is snapshotted.
update [--write] mutator The whole plan as ONE snapshotted batch: git pull git skills (which also refreshes their refs), replace adopted skills from their origin tarball at the exact target SHA (staging + swap — upstream deletions apply), pin/bump MCP servers in every config check reads, refresh plugin marketplaces (CLI refresh and our own clone pull — the CLI reports success without pulling).
pin [--write] mutator Pin floating npx/uvx servers to their latest version, in the config file each entry lives in.
restore [snapshot] safety net Put a whole batch back: changed files copied back, created files deleted. restore latest undoes the last batch.
selftest — Run the bundled offline unit tests (each one named after the promise it guards).

What it reads (check and mutators agree on this list)

  • Skills: ~/.zcode/skills/, ~/.agents/skills/ (git repos, adopted entries, plain orphans). Parked dirs (skills.disabled, archives) are counted, not scanned.
  • MCP servers: ~/.claude.json (user + project scopes) and ./.mcp.json — update rewrites the exact file each entry came from.
  • Plugins: Claude-Code-style plugin/marketplace registries under ~/.zcode/cli/plugins/.
  • Network: npm/PyPI registry metadata, GitHub API + tarballs, git remotes. Nothing is sent anywhere; no telemetry, ever.

Design decisions

See docs/adr/ — cross-layer scope, the never-breaks contract (includes the hardening amendments from the first external review), stdlib + uvx, and adoption over re-cloning. The project vocabulary lives in CONTEXT.md.

Roadmap

  • PyPI packaging (uvx driftcheck).
  • Multi-client MCP adapters (Codex, Cursor config formats).
  • Snapshot housekeeping (restore --prune).
  • Heuristic adopt --scan (fingerprint orphan SKILL.md against GitHub search).

Community

Status

Validated against a real arsenal (104 skills, 102 orphans, 7 MCP servers, 46-day-stale marketplaces), hardened by an adversarial two-axis external review (each finding guarded by a named unit test), and then taken from zero through an old-school E2E campaign (tests/e2e_campaign.py): 15 scenarios running the real CLI inside a sandboxed HOME against a fabricated arsenal with real GitHub/npm traffic — covering empty worlds, full censuses, byte-level dry-run purity (including .git, so no hidden fetches survive), single-snapshot batches, whole-batch byte-identical restores, the complete adopted lifecycle, every rejection path, abort-on- snapshot-failure with zero mutations, corrupt inputs, offline degradation, and execution under the system Python 3.9. The campaign itself caught and killed three more real bugs before first publish.

About

The cross-layer updater for agent skills, MCP servers, and plugins — one drift picture, one snapshotted update path, one command to undo any of it.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages