Help us improve
Share bugs, ideas, or general feedback.
From drift-detect
Use when the user asks about plan drift, reality check, comparing docs to code, project state analysis, roadmap alignment, implementation gaps, or needs guidance on identifying discrepancies between documented plans and actual implementation state.
npx claudepluginhub agent-sh/drift-detect --plugin drift-detectHow this skill is triggered — by the user, by Claude, or both
Slash command
/drift-detect:drift-analysisThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Knowledge and patterns for analyzing project state, detecting plan drift, and creating prioritized reconstruction plans.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
Applies a firm's KYC/AML rules grid to parsed onboarding records: assigns risk rating, checks required documents, outputs rule outcomes with citations, and routes for escalation.
Designs test strategies and plans with testing pyramid. Covers APIs, frontend, data pipelines, infrastructure; outputs plans including coverage targets, examples, and gaps.
Share bugs, ideas, or general feedback.
Knowledge and patterns for analyzing project state, detecting plan drift, and creating prioritized reconstruction plans.
/drift-detect
│
├─→ collectors.js (pure JavaScript)
│ ├─ scanGitHubState()
│ ├─ analyzeDocumentation()
│ ├─ scanCodebase()
│ └─ getRepoIntelSignals() (optional, via agent-analyzer binary)
│
└─→ plan-synthesizer (Sonnet)
└─ Deep semantic analysis with full context
Data collection: Pure JavaScript (no LLM overhead) Semantic analysis: Single Sonnet call with complete context
Plan Drift: When documented plans diverge from actual implementation
Documentation Drift: When documentation falls behind implementation
Issue Drift: When issue tracking diverges from reality
Scope Drift: When project scope expands beyond original plans
HIGH-CONFIDENCE DRIFT INDICATORS:
- Milestone 30+ days overdue with open issues
- PLAN.md < 30% completion after 90 days
- 5+ high-priority issues stale > 60 days
- README features not found in codebase
MEDIUM-CONFIDENCE INDICATORS:
- Documentation files unchanged for 180+ days
- Draft PRs open > 30 days
- Issue themes don't match code activity
- Large gap between documented and implemented features
LOW-CONFIDENCE INDICATORS:
- Many TODOs in codebase
- Stale dependencies
- Old git branches not merged
function calculatePriority(item, weights) {
let score = 0;
// Severity base score
const severityScores = {
critical: 15,
high: 10,
medium: 5,
low: 2
};
score += severityScores[item.severity] || 5;
// Category multiplier
const categoryWeights = {
security: 2.0, // Security issues get 2x
bugs: 1.5, // Bugs get 1.5x
infrastructure: 1.3,
features: 1.0,
documentation: 0.8
};
score *= categoryWeights[item.category] || 1.0;
// Recency boost
if (item.createdRecently) score *= 1.2;
// Stale penalty (old items slightly deprioritized)
if (item.daysStale > 180) score *= 0.9;
return Math.round(score);
}
| Bucket | Criteria | Max Items |
|---|---|---|
| Immediate | severity=critical OR priority >= 15 | 5 |
| Short-term | severity=high OR priority >= 10 | 10 |
| Medium-term | priority >= 5 | 15 |
| Backlog | everything else | 20 |
security: 10 # Security issues always top priority
bugs: 8 # Bugs affect users directly
features: 5 # New functionality
documentation: 3 # Important but not urgent
tech-debt: 4 # Keeps codebase healthy
// Fuzzy matching for feature names
function featureMatch(docFeature, codeFeature) {
const normalize = s => s
.toLowerCase()
.replace(/[-_\s]+/g, '')
.replace(/s$/, ''); // Remove trailing 's'
const docNorm = normalize(docFeature);
const codeNorm = normalize(codeFeature);
return docNorm.includes(codeNorm) ||
codeNorm.includes(docNorm) ||
levenshteinDistance(docNorm, codeNorm) < 3;
}
| Documented As | Implemented As |
|---|---|
| "user authentication" | auth/, login/, session/ |
| "API endpoints" | routes/, api/, handlers/ |
| "database models" | models/, entities/, schemas/ |
| "caching layer" | cache/, redis/, memcache/ |
| "logging system" | logger/, logs/, telemetry/ |
## Drift Analysis
### {drift_type}
**Severity**: {severity}
**Detected In**: {source}
{description}
**Evidence**:
{evidence_items}
**Recommendation**: {recommendation}
## Gap: {gap_title}
**Category**: {category}
**Severity**: {severity}
{description}
**Impact**: {impact_description}
**To Address**:
1. {action_item_1}
2. {action_item_2}
## Reconstruction Plan
### Immediate Actions (This Week)
{immediate_items_numbered}
### Short-Term (This Month)
{short_term_items_numbered}
### Medium-Term (This Quarter)
{medium_term_items_numbered}
### Backlog
{backlog_items_numbered}
Compare timestamps, not just content
Look for patterns, not individual items
Consider context
Weight by impact
Be actionable, not exhaustive
Group related items
Include success criteria
Balance categories
Before collecting data, check if the repo-intel map exists:
const fs = require('fs');
const path = require('path');
const cwd = process.cwd();
const stateDir = ['.claude', '.opencode', '.codex']
.find(d => fs.existsSync(path.join(cwd, d))) || '.claude';
const mapFile = path.join(cwd, stateDir, 'repo-intel.json');
if (!fs.existsSync(mapFile)) {
const response = await AskUserQuestion({
questions: [{
question: 'Generate repo-intel?',
description: 'No repo-intel map found. Generating one enables doc-drift and area health analysis. Takes ~5 seconds.',
options: [
{ label: 'Yes, generate it', value: 'yes' },
{ label: 'Skip', value: 'no' }
]
}]
});
if (response === 'yes' || response?.['Generate repo-intel?'] === 'yes') {
try {
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT;
if (!pluginRoot) throw new Error('CLAUDE_PLUGIN_ROOT not set');
const { binary } = require(`${pluginRoot}/lib/agentsys`).get();
const output = binary.runAnalyzer(['repo-intel', 'init', cwd]);
const stateDirPath = path.join(cwd, stateDir);
if (!fs.existsSync(stateDirPath)) fs.mkdirSync(stateDirPath, { recursive: true });
fs.writeFileSync(mapFile, output);
} catch (e) {
console.error(`[INFO] repo-intel init skipped: ${e.message}`);
}
}
}
The collectors.js module extracts data without LLM overhead:
docDrift: Doc files with low code coupling (likely stale, never co-change with code)areas: Directory-level health - owners, hotspot score, bug-fix rate, health status (healthy/needs-attention/at-risk)Structural code-fact signals from the slop-precision detectors. Summarized for the agent's context budget (top 20-30 of each category):
orphanExports: symbols exported but never imported - abandoned or scope-dropped featurespassthroughWrappers: single-call delegation functions - often indicates an abstraction that didn't landalwaysTrueConditions: if (x == x) / contradictions - bugs or dead branchesdocDrift: doc files with low code coupling, already filtered against versioned_docs/fixtures/generatedstaleDocsSample: per-doc per-line removed-symbol references - precise doc-drift evidenceentryPoints: binaries, main() functions, framework configs - execution surfaces that don't need prose docsThe plan-synthesizer receives all collected data and performs:
{
"github": {
"issues": [...],
"categorized": { "bugs": [...], "features": [...] },
"stale": [...]
},
"docs": {
"files": { "README.md": {...}, "PLAN.md": {...} },
"checkboxes": { "total": 15, "checked": 3 }
},
"code": {
"frameworks": ["Express"],
"health": { "hasTests": true, "hasCi": true }
},
"repoIntel": {
"docDrift": [{"path": "README.md", "codeCoupling": 0, "lastChanged": "2025-01-15", "changes": 5}],
"areas": [{"area": "src/auth/", "files": 8, "owners": [...], "hotspotScore": 3.2, "bugFixRate": 0.25, "health": "at-risk"}]
},
"analyzer": {
"available": true,
"counts": { "staleDocs": 42, "orphanExports": 3, "passthroughWrappers": 1, "alwaysTrueConditions": 0 },
"orphanExports": [{"action": {"path": "src/legacy.rs", "lines": [12, 25]}, "reason": "fn `legacyHandler` is exported but never imported", "confidence": 0.75}],
"passthroughWrappers": [{"action": {"path": "src/api.rs", "lines": [45, 48]}, "reason": "Rust `fn get_user(id)` is a single-call passthrough to `fetch_user` with identical args", "confidence": 0.85}],
"alwaysTrueConditions": [],
"docDrift": [],
"staleDocsSample": [{"doc": "README.md", "line": 42, "reference": "legacyHandler", "issue": "symbol-not-found"}],
"entryPoints": [{"path": "src/main.rs", "name": "main", "kind": "main"}]
}
}
# Reality Check Report
## Executive Summary
Project has moderate drift: 8 stale priority issues and 20% plan completion.
Strong code health (tests + CI) but documentation lags implementation.
## Drift Analysis
### Priority Neglect
**Severity**: high
8 high-priority issues inactive for 60+ days...
## Prioritized Plan
### Immediate
1. Close #45 (already implemented)
2. Update README API section...