Knowledge Base Lint
Periodic health-check for the project's knowledge base. This is the lint operation in the three-operations model (ingest / query / lint), adopted from Karpathy's LLM Wiki gist.
The staleness check that runs in environment validation catches one kind of drift (file changed since last index). Lint catches the other kinds: logical drift, orphan accumulation, missing concepts, contradictions, gaps. Both are needed.
Arguments
Optional --scope <pattern> to limit lint to a subset of library files. Default is the entire library.
Optional --strict-layer to fail with a non-zero exit when any library file has a missing or invalid layer: frontmatter field. Without this flag, layer violations are reported as warnings only in the Layer Compliance section.
Optional --strict-confidence to fail with a non-zero exit when any library file has a missing or invalid confidence: field. Without this flag, confidence violations are reported as warnings in the Layer Compliance section.
Optional --auto-fix to run the mechanical frontmatter fixer (kb_lint_fix.py) before lint. Auto-fix adds missing layer:, confidence:, and cross_references: fields with safe defaults, and creates stub frontmatter (with confidence: low, status: draft) for files that have no frontmatter at all. After fixing, the shelf-index is rebuilt before lint proceeds.
Examples:
--scope dora-*.md— lint only DORA-related files--scope library/architecture/*.md— lint a sub-directory--strict-layer— enforce layer compliance (used by this repo's CI)--strict-layer --scope *.md— combine both--strict-confidence— enforce confidence compliance--auto-fix --strict-layer --strict-confidence— fix mechanics, then enforce both- (no argument) — lint everything, warnings only
Preflight
- Verify the knowledge base is configured.
- Verify the shelf-index is fresh: invoke
kb-rebuild-indexesfirst if any library files are newer than the index. (The lint output is only meaningful against an up-to-date index.) - Verify there are at least 3 library files. Linting an empty or near-empty library is not useful.
Steps
-1. Auto-fix mechanical issues (only when --auto-fix is passed)
If --auto-fix was passed, run the mechanical fixer before any other step:
python3 -c "
import sys, os, importlib.util
PLUGIN_ROOT = os.environ.get('CLAUDE_PLUGIN_ROOT', '')
SCRIPTS = os.path.join(PLUGIN_ROOT, 'scripts')
INIT = os.path.join(SCRIPTS, '__init__.py')
if os.path.isfile(INIT) and 'sdlc_knowledge_base_scripts' not in sys.modules:
spec = importlib.util.spec_from_file_location(
'sdlc_knowledge_base_scripts', INIT,
submodule_search_locations=[SCRIPTS])
if spec and spec.loader:
mod = importlib.util.module_from_spec(spec)
sys.modules['sdlc_knowledge_base_scripts'] = mod
spec.loader.exec_module(mod)
from sdlc_knowledge_base_scripts.kb_lint_fix import fix_missing_fields
from pathlib import Path
result = fix_missing_fields(Path('<library_path>'))
print(f'Auto-fix: {result.files_fixed} file(s) fixed, {result.fields_added} field(s) added')
if result.errors:
print(f'Errors: {result.errors}')
"
Replace <library_path> with the resolved library path from the KB config.
After fixing, run kb-rebuild-indexes to update the shelf-index before proceeding to Step 0.
If --auto-fix was NOT passed, skip this step entirely.
0. Layer compliance check (always runs)
Run the pure-Python layer compliance check:
python3 -c "
import sys, os, importlib.util
PLUGIN_ROOT = os.environ.get('CLAUDE_PLUGIN_ROOT', '')
SCRIPTS = os.path.join(PLUGIN_ROOT, 'scripts')
INIT = os.path.join(SCRIPTS, '__init__.py')
if os.path.isfile(INIT) and 'sdlc_knowledge_base_scripts' not in sys.modules:
spec = importlib.util.spec_from_file_location(
'sdlc_knowledge_base_scripts', INIT,
submodule_search_locations=[SCRIPTS])
if spec and spec.loader:
mod = importlib.util.module_from_spec(spec)
sys.modules['sdlc_knowledge_base_scripts'] = mod
spec.loader.exec_module(mod)
from sdlc_knowledge_base_scripts.kb_config import allowed_layers, check_layer_compliance
from pathlib import Path
layers = allowed_layers(Path('.'))
violations = check_layer_compliance(Path('<library_path>'), layers)
if violations:
for path, msg in violations:
print(f' {path}: {msg}')
sys.exit(1)
else:
sys.exit(0)
"
Replace <library_path> with the resolved library path from the KB config.
If this exits non-zero AND --strict-layer was passed: stop and report the Layer Compliance violations. Do not proceed to Step 1. Exit non-zero.
If this exits non-zero but --strict-layer was NOT passed: record the violations as warnings and continue to Step 1 — include them in the "Layer Compliance" section of the lint report.
If this exits zero: no layer issues. Continue to Step 1.
Also run confidence compliance in the same Step 0 pass:
python3 -c "
import sys, os, importlib.util
PLUGIN_ROOT = os.environ.get('CLAUDE_PLUGIN_ROOT', '')
SCRIPTS = os.path.join(PLUGIN_ROOT, 'scripts')
INIT = os.path.join(SCRIPTS, '__init__.py')
if os.path.isfile(INIT) and 'sdlc_knowledge_base_scripts' not in sys.modules:
spec = importlib.util.spec_from_file_location(
'sdlc_knowledge_base_scripts', INIT,
submodule_search_locations=[SCRIPTS])
if spec and spec.loader:
mod = importlib.util.module_from_spec(spec)
sys.modules['sdlc_knowledge_base_scripts'] = mod
spec.loader.exec_module(mod)
from sdlc_knowledge_base_scripts.confidence import check_confidence_compliance
from pathlib import Path
conf_violations = check_confidence_compliance(Path('<library_path>'))
if conf_violations:
for path, msg in conf_violations:
print(f' {path}: {msg}')
sys.exit(1 if <strict_confidence> else 0)
else:
print('Confidence compliance: OK')
sys.exit(0)
"
Replace <library_path> with the resolved path. Replace <strict_confidence> with True if --strict-confidence was passed.
If this exits non-zero AND --strict-confidence was passed: stop and report the confidence violations. Otherwise continue to Step 1.
1. Read the shelf-index
Use the index to enumerate library files. Apply the --scope filter if provided.
2. Run six checks
For each library file in scope, the librarian agent (in lint mode) performs the following checks:
Check 1: Contradictions between files
Look for findings in different files that disagree. Flag any case where:
- Two files report different numbers for the same metric
- Two files cite different sources for the same claim
- Two files draw opposite conclusions from similar evidence
For each contradiction, report:
- The conflicting findings (with their source files and citations)
- A suggested resolution: one source is more authoritative, both are valid in different contexts, or genuine disagreement that needs human judgment
Check 2: Stale claims
Look for findings whose citation date is significantly older than the most recent file in the same domain. Heuristic:
- If file A cites a 2018 source and file B (same domain) cites a 2024 source with updated numbers, file A's findings may be stale
- If a file's
## Programme Relevancereferences project artifacts that no longer exist or have evolved (e.g., deleted issues, renamed components), the section may be stale
For each stale candidate, report:
- The potentially stale finding
- The newer source that suggests it's stale
- A recommendation: review and update, or annotate as historical
Check 3: Orphan files
Files with no inbound cross-references from other library files. An orphan is either:
- A genuinely standalone file (acceptable, but consider whether it should be cross-referenced from related domains)
- A file that should be cross-referenced but isn't (a maintenance gap)
For each orphan, report:
- The file path
- A list of files that mention the orphan's domain or terms in their content (suggesting they should cross-reference it)
Check 4: Missing cross-references
Files that mention a concept by name where another library file exists for that concept, but the cross-reference isn't declared in frontmatter. Use Grep against the library to find:
- File X's content mentions "DORA metrics" → if
dora-metrics.mdexists and isn't in X'scross_references, flag it
For each missing cross-reference, report:
- The file that should reference
- The file it should reference
- The text in the source file that triggered the suggestion
Check 5: Important concepts lacking their own page
Look for terms or topics that appear repeatedly across multiple library files but have no dedicated file. Heuristic:
- A term appears in 3+ files but has no file with that term in its title or domain → consider creating a dedicated file
For each candidate, report:
- The term or topic
- The files that mention it
- A recommendation: consider creating a dedicated library file (or skip if the concept is too broad to be useful as its own page)
Check 6: Data gaps
Look for places where the library would benefit from research it doesn't have. Heuristic:
- A file's
## Frameworks Reviewedmentions a framework but has no## Core Findingsfor it → research gap - A file's
## Actionable Thresholdstable has a row with no Source → unsourced threshold needs verification - A
## Key Questionwhose## Core Findingsdoesn't actually answer it
For each gap, report:
- The file with the gap
- What's missing
- A suggested next step (commission research via
kb-ingest, find the source for the unsourced threshold, etc.)
3. Produce the structured report
Output format:
# Knowledge Base Lint Report
**Date:** YYYY-MM-DD
**Scope:** all files (or pattern)
**Files scanned:** N
## Summary
| Check | Issues found |
|---|---|
| 0. Layer compliance | L |
| 1. Contradictions | C |
| 2. Stale claims | S |
| 3. Orphan files | O |
| 4. Missing cross-references | X |
| 5. Concepts lacking pages | M |
| 6. Data gaps | G |
**Total issues:** TOTAL
---
## 0. Layer Compliance
Files with missing or invalid `layer:` values:
(List each file with the specific violation, or "None" if all compliant)
## 1. Contradictions
### 1.1 [Conflicting topic]
**File A:** dora-metrics.md — "Elite teams have cycle time <1 hour, n=39000 (DORA 2024)"
**File B:** continuous-delivery-evidence.md — "Top performers achieve cycle time <30 minutes, n=12 (Bytedance 2025)"
**Suggested resolution:** Both are valid in different contexts. DORA 2024 is the broader cross-industry benchmark; Bytedance is a single-org case study with stricter internal targets. Suggest annotating both files to distinguish industry-wide vs single-org thresholds.
(Continue for each contradiction...)
## 2. Stale claims
(...)
## 3. Orphan files
(...)
## 4. Missing cross-references
(...)
## 5. Concepts lacking pages
(...)
## 6. Data gaps
(...)
---
## Recommended actions (prioritised)
1. [Highest-priority issue]
2. [Next-priority issue]
3. ...
4. Append to log.md
If library/log.md exists, append:
## [YYYY-MM-DD] lint | <total issues>
Mode: full (or scoped: <pattern>)
Files scanned: N
Contradictions: C
Stale claims: S
Orphan files: O
Missing cross-references: X
Concepts lacking pages: M
Data gaps: G
5. Do NOT auto-fix
The lint operation is read-only and reports issues. It does not:
- Automatically resolve contradictions
- Automatically add cross-references
- Automatically create new files for missing concepts
- Automatically annotate stale claims
The user reviews the report and decides what to act on. Some issues are real maintenance work; others are intentional (an orphan file may be standalone by design; a contradiction may be a known disagreement worth preserving).
For issues the user wants to fix, the workflow is:
- Manual: edit the library files directly, then run
kb-rebuild-indexes - Automated: run
kb-ingestwith new sources that resolve the gap, runkb-rebuild-indexes, re-runkb-lint
What this skill does NOT do
- It does not invoke
kb-rebuild-indexesautomatically (preflight checks for staleness and recommends it, but doesn't run it) - It does not modify any library files
- It does not query the library on behalf of users — that's
kb-query - It does not validate citations — that's
kb-validate-citations
Examples
Lint the entire library:
/sdlc-knowledge-base:kb-lint
Lint a subset:
/sdlc-knowledge-base:kb-lint --scope dora-*.md
After fixes, re-lint to confirm:
/sdlc-knowledge-base:kb-lint
# Apply the fixes manually
/sdlc-knowledge-base:kb-rebuild-indexes
/sdlc-knowledge-base:kb-lint # confirm issues are resolved
Errors
- No knowledge base configured — run
/sdlc-knowledge-base:kb-initfirst - Shelf-index stale — run
/sdlc-knowledge-base:kb-rebuild-indexesfirst - Library too small — fewer than 3 files; lint produces little value at this scale. Add more files first.
- Scope pattern matches nothing — verify the pattern matches at least one file in the library
- Layer violations in strict mode — one or more library files have missing or invalid
layer:field. Addlayer:to each file and run/sdlc-knowledge-base:kb-rebuild-indexes. Run/sdlc-knowledge-base:kb-layersto see the project's allowed layer vocabulary. - Confidence violations in strict mode — files have missing or invalid
confidence:field. Run/sdlc-knowledge-base:kb-lint --auto-fixto addconfidence: mediumto files missing it, then re-run with--strict-confidence.