drift-kit
Drift reporting for coding-agent sessions. Gates block what a single diff makes mechanically decidable; drift is what accumulates between commits — a backlog ages, an always-loaded surface swells, friction recurs, and every stateless session looks fine because none of them ever sees the slope. drift-kit is that trend surface: an advisory --emit drift-report arm that collates pluggable KPIs from the other kits’ governed surfaces, groups them under honest weight labels (lead — act before drift compounds; lag — undercounts by construction), and emits a one-line trend summary the session-start hook injects, so every session opens seeing the slope it cannot otherwise see.
Advisory by construction: the report exits 0, never fails a session, and reads trend, not level — a KPI’s absolute value is noise; its direction across sessions is the signal. See SPEC.md for the report frame, the plugin contract, the bundled KPI set, and the knowledge-friction loop.
This file ships in the installer payload; what that payload withholds, and where this page’s SPEC.md links then resolve, is gate-sdk/SPEC.md §Consumer payload.
drift-kit registers no gates: its surface is a set of advisory --emit arms and a KPI registry, so nothing joins gates.list. It follows gate-sdk’s resolution and smoke conventions without depending on its registry.
Install
Vendor the kit beside gate-sdk, then:
-
Copy the registry and config into your gates dir (default
scripts/):cp drift-kit/templates/kpis.list scripts/kpis.list cp drift-kit/templates/drift-config.knobs scripts/drift-config.knobs # optionalPrune
scripts/kpis.listto the KPIs whose surfaces your repo has; each bundled KPI degrades to a visiblen/arow when its surface is absent, so an over-broad registry is safe but noisy. -
Wire the trend line — point context-kit’s session-context hook at the report by setting
CONTEXT_KIT_DRIFT_REPORTto the arm namedrift-reportin your context-kit knob file. The hook runs the arm with--trendand prints one line; left unset, the line is silently skipped.
Configuration follows the established kit pattern — override any knob in drift-config.knobs (registry path, extra KPI dirs, the queue/log/timings surfaces, the metric dir holding the persistent trend logs, the Done/Deferred section headings); defaults are this repo’s layout. Keep the metric dir (DRIFT_KIT_METRIC_DIR; drift-kit/SPEC.md §Layout and configuration owns the default) gitignored — its trend samples carry account and session identifiers.
The knowledge-friction loop (optional)
kpi-knowledge-friction measures re-derivations a session had to make because no doc owned the fact (drift-kit/SPEC.md §The knowledge-friction loop). It shows n/a until you install the capture half:
- Add one bullet to your always-loaded instructions file: the moment you catch yourself re-deriving a fact off a non-owning surface, append
<date> <fact> ← <surface>to.workflow/knowledge-friction.log. That bullet is the loop’s only hook — earn its cost by the log actually filling. The--emit kfric [--] "<fact>" "<surface>"arm on the gate binaryGATE_SDK_NATIVE_BINnames is the shipped affordance that stamps that grammar prompt-free — both fields required non-empty in that order,--files one beginning with a dash, and a refusal,--helpincluded, prints the usage at exit 2. Raw append stays legal (drift-kit/SPEC.md §The knowledge-friction loop). - Gitignore the log (per-iteration scratch) and its drain companions (
.workflow/*.drain,.workflow/*.drain.part), and splicetemplates/close-knowledge.mdinto your close skill so each entry is re-verified, becomes the tiering edit or the correction that outcome selects, and the drained log is removed — its reclaim path.
Use
Run these arms with the gate binary GATE_SDK_NATIVE_BIN names, where init places it. In PowerShell, spell each line ./scripts/checkwright-gates <arm> at the repository root, with .exe on native Windows:
gates="${GATE_SDK_NATIVE_BIN:-./scripts/checkwright-gates}"
"$gates" --emit drift-report # full report: lead/lag rows under the honesty labels
"$gates" --emit drift-report --trend # one compact line (fragments joined with ·)
"$gates" --emit trajectory # governed-trajectory table (one row per closed iteration)
"$gates" --emit queue-flow [<n>] # design-pending pool filed/drained per trailing iteration, plus mean-filed
"$gates" --emit overhead-meter # governance-vs-task byte proxy for this session's transcript (a delegated session passes its transcript or stamp id)
"$gates" --emit stage-economics # real spend by stage × model × iteration (stamps ⋈ transcripts ⋈ price table)
"$gates" --emit manual-ops [iteration] # the shell shapes and hand-edited paths an iteration's sessions repeated, ranked as tooling candidates
"$gates" --price-coverage # which running model ids the price table cannot price; with a page command set, whether the pricing page moved
"$gates" --emit file-install [--author] [--] <kind> <field>... # record one observed install, red or check-in (three kinds, three arities); --author files the author seat's own
"$gates" --emit install-evidence # the aggregate-only projection over that record, for a consumer to pin behind a freshness gate
--emit overhead-meter is the overhead meter (drift-kit/SPEC.md §The overhead meter): a byte-proxy over a session transcript that reports what fraction of the volume was governance versus task work, logging one line per session for kpi-overhead — the methodology’s own cost, measured so efficiency claims cut both ways. Advisory and content-free: it emits counts only, never transcript text.
The trajectory emit arm is the published-evidence extractor (drift-kit/SPEC.md §The published-evidence extractor): a pure function of committed git history that emits one row per closed iteration — stages run, commit shape, amendment latency, validate attestations, gate-roster growth — for a consumer to pin behind a freshness gate.
--emit queue-flow is the queue-flow arm (drift-kit/SPEC.md §The queue-flow arm): kpi-queue-net-delta’s filed and drained counts over each of the trailing closed iterations, and their mean inflow, the figure a scope session weighs a unit set against.
--emit stage-economics is the stage-economics meter (drift-kit/SPEC.md §The stage-economics meter): it prices real spend by lifecycle stage × model × iteration by joining WORKFLOW-STATE stamps to their session transcripts to a consumer-supplied price table, keeping the cache-read burn lever visible close-over-close. Copy templates/price-table.tsv beside your gates dir and fill your model roster (the roster is consumer config, never a kit literal — the provenance seam); absent it, cost degrades to n/a and tokens still report. The /economics skill (templates/economics.md, materialized in your agent-skill directory) chains overhead-meter → stage-economics → manual-ops into one post-iteration cost narrative — a reporting ritual the close skill may invoke, not a lifecycle stage and not a gate. If your decisions read the log, run the meter at your terminal stage — its rows are dated by their stamps, so a re-run at every close re-dates nothing — and kpi-stage-economics-lag shows how many closes have gone unpriced when that feed is skipped.
--emit manual-ops is the manual-operation meter (drift-kit/SPEC.md §The manual-operation meter): over the transcripts the stage-economics meter attributes to an iteration, it ranks the shell shapes and repository paths edited by hand, with how many iterations each has ranked in, so the close can see where a tool would remove work. Set DRIFT_KIT_MANUAL_OPS_IGNORE to the shapes you count as ordinary work. Advisory and content-free: it prints keys and counts, never command text.
--emit file-install and --emit install-evidence are the two halves of the install-observation channel (drift-kit/SPEC.md §The install-observation record and §The install-evidence projection): the first appends one dated line per install, per red a non-author hit, and per retention check-in to a private, gitignored record under your metric dir (--author files an install you or someone acting for you ran into a separate record the projection never reads, so author evidence never reaches a published figure); the second emits an aggregate-only markdown table set over it — every figure with its denominator, no row keyed to a single install, and <id>, <profile> and <floor> never published. The field set is fixed before the first observation on purpose: a red nobody wrote down was never observed, so the evidence cannot be collected retrospectively. Closed-set fields are enforced at capture, so the arm’s refusals are the whole observation protocol.
A KPI plugin is kpi-<name>.sh, resolved through kpis.list against your KPI dirs, then each vendored kit’s kpis/, then the binary’s built-in members — three tiers, consumer-first. Add your own by dropping a plugin in your gates dir and naming it in the registry; shadow a bundled one with a same-named file. Your plugin is executed directly and reads the exported DRIFT_KIT_* environment, both unchanged by the bundled set moving in-crate. The bundled set (drift-kit/SPEC.md §Bundled KPIs) carries, as lead KPIs, kpi-task-split, kpi-queue-net-delta, kpi-gate-backlog, kpi-amendment-age, kpi-deferred-age, kpi-deprecated-surface, kpi-prompt-friction, kpi-always-loaded, kpi-settings-local, kpi-gate-runtime, kpi-overhead, kpi-price-table-age and kpi-stage-economics-lag; and as lag KPIs, kpi-knowledge-friction (fed by the loop below) and kpi-incident-recurrence (fed by the queue’s [recurrence:] tags).
Test
Run this arm the same way, from a source clone or a hand-vendored copy: it installs each kit from its smoke/ (gate-sdk/SPEC.md §Consumer payload).
gates="${GATE_SDK_NATIVE_BIN:-./scripts/checkwright-gates}"
"$gates" --run-consumer-smoke drift-kit # report contract: sections, per-KPI rows, degradation, one-line --trend
License
Licensed under Apache-2.0, with the text in LICENSE beside this file in an installed copy and at the repository root in the source tree.