@adia-ai/adia-ui-forge 0.1.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +3 -6
- package/CHANGELOG.md +27 -34
- package/README.md +35 -40
- package/agents/a2ui-engineer.md +22 -53
- package/agents/component-author.md +29 -0
- package/agents/framework-verifier.md +26 -0
- package/agents/release-engineer.md +21 -81
- package/agents/routing-corpus.json +293 -64
- package/bin/demo-postwrite-pattern-gate +94 -0
- package/bin/forge-lint +17 -2
- package/bin/sidecar-prewrite-guard +104 -0
- package/commands/deploy.md +9 -0
- package/commands/dogfood.md +10 -0
- package/commands/gen-review.md +9 -0
- package/commands/release.md +10 -0
- package/hooks/hooks.json +15 -0
- package/package.json +3 -6
- package/references/contracts/a2ui-mcp-surface.md +35 -0
- package/references/contracts/migration-guide-format.md +34 -0
- package/references/shared/content-trust.md +19 -74
- package/skills/adia-a2ui/SKILL.md +99 -0
- package/skills/{adia-ui-a2ui → adia-a2ui}/evals/routing-corpus.json +10 -10
- package/skills/adia-a2ui/references/anti-patterns.md +27 -0
- package/skills/adia-a2ui/references/chunk-authoring.md +71 -0
- package/skills/adia-a2ui/references/corpus-discipline.md +68 -0
- package/skills/adia-a2ui/references/eval-diagnostics.md +86 -0
- package/skills/adia-a2ui/references/format-extension-decisions.md +66 -0
- package/skills/adia-a2ui/references/leverage-rules.md +52 -0
- package/skills/adia-a2ui/references/mcp-pipeline-ops.md +83 -0
- package/skills/adia-a2ui/references/mcp-tool-reference.md +59 -0
- package/skills/adia-a2ui/references/pipeline-overview.md +115 -0
- package/skills/adia-a2ui/references/semantic-fail-lifting.md +74 -0
- package/skills/adia-a2ui/references/strategy-engines.md +109 -0
- package/skills/adia-a2ui/references/zettel-calibration.md +104 -0
- package/skills/adia-author/SKILL.md +112 -0
- package/skills/adia-author/evals/routing-corpus.json +222 -0
- package/skills/{adia-ui-authoring → adia-author}/references/anti-patterns.md +33 -4
- package/skills/{adia-ui-authoring → adia-author}/references/authoring-cycle.md +9 -11
- package/skills/adia-author/references/canonical-pattern-index.md +243 -0
- package/skills/{adia-ui-authoring → adia-author}/references/code-style.md +19 -21
- package/skills/adia-author/references/common-gotchas.md +129 -0
- package/skills/adia-author/references/composite-demo-protocol.md +271 -0
- package/skills/{adia-ui-authoring → adia-author}/references/css-patterns.md +19 -6
- package/skills/{adia-ui-authoring → adia-author}/references/lifecycle-patterns.md +1 -0
- package/skills/{adia-ui-authoring → adia-author}/references/llm-bridge.md +3 -5
- package/skills/{adia-ui-authoring → adia-author}/references/module-promotion.md +20 -38
- package/skills/{adia-ui-authoring → adia-author}/references/primitive-audit.md +2 -4
- package/skills/{adia-ui-authoring → adia-author}/references/shell-patterns.md +12 -18
- package/skills/{adia-ui-authoring → adia-author}/references/token-contract.md +5 -7
- package/skills/{adia-ui-authoring → adia-author}/references/worked-example.md +3 -3
- package/skills/{adia-ui-authoring → adia-author}/references/yaml-contract.md +3 -3
- package/skills/{adia-ui-authoring → adia-author}/scripts/build-canonical-pattern-index.mjs +3 -3
- package/skills/adia-deploy/SKILL.md +128 -0
- package/skills/{adia-ui-ops → adia-deploy}/references/deploy-playbooks.md +47 -30
- package/skills/adia-dogfood/SKILL.md +124 -0
- package/skills/adia-dogfood/references/admin-shell-anatomy.md +77 -0
- package/skills/adia-dogfood/references/app-shell-pitfalls.md +66 -0
- package/skills/adia-dogfood/references/card-anatomy-sweep.md +66 -0
- package/skills/adia-dogfood/references/html-attr-sweep.md +63 -0
- package/skills/adia-dogfood/references/native-leak-annotations.md +73 -0
- package/skills/adia-dogfood/references/visual-probe-triage.md +80 -0
- package/skills/{adia-ui-dogfood → adia-dogfood}/scripts/analyze.mjs +30 -14
- package/skills/adia-gen-review/SKILL.md +127 -0
- package/skills/adia-gen-review/references/corpus-html-patterns.md +279 -0
- package/skills/adia-gen-review/references/loop-protocol.md +216 -0
- package/skills/adia-gen-review/references/rubric-cosmetic.md +100 -0
- package/skills/adia-gen-review/references/rubric-decompose.md +101 -0
- package/skills/adia-gen-review/references/rubric-score.md +214 -0
- package/skills/{adia-ui-gen-review → adia-gen-review}/references/scores.schema.json +2 -2
- package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-coverage-audit.mjs +4 -4
- package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-decompose.mjs +10 -6
- package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-status.mjs +5 -5
- package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/validate-cycle-scores.mjs +5 -5
- package/skills/adia-llm-internals/SKILL.md +77 -0
- package/skills/{adia-ui-llm → adia-llm-internals}/references/adapter-contract.md +4 -2
- package/skills/{adia-ui-llm → adia-llm-internals}/references/add-a-provider.md +4 -5
- package/skills/{adia-ui-llm → adia-llm-internals}/references/bridge-facade.md +10 -3
- package/skills/{adia-ui-llm → adia-llm-internals}/references/browser-proxy-boundary.md +1 -1
- package/skills/{adia-ui-llm → adia-llm-internals}/references/model-registry.md +5 -3
- package/skills/{adia-ui-llm → adia-llm-internals}/references/streaming-sse.md +2 -2
- package/skills/adia-release/SKILL.md +72 -0
- package/skills/adia-release/references/changelog-discipline.md +119 -0
- package/skills/adia-release/references/cut-procedure.md +247 -0
- package/skills/adia-release/references/gates-catalog.md +222 -0
- package/skills/adia-release/references/independent-package-release.md +52 -0
- package/skills/adia-release/references/migration-guide-authoring.md +86 -0
- package/skills/adia-release/references/notes-authoring.md +90 -0
- package/skills/adia-release/references/recovery-paths.md +106 -0
- package/skills/{adia-ui-release → adia-release}/scripts/bump.mjs +27 -2
- package/skills/{adia-ui-release → adia-release}/scripts/dispatch-publish.mjs +4 -1
- package/skills/{adia-ui-release → adia-release}/scripts/insert-stub.mjs +1 -1
- package/skills/{adia-ui-release → adia-release}/scripts/package-paths.mjs +6 -0
- package/skills/{adia-ui-release → adia-release}/scripts/promote-unreleased.mjs +1 -1
- package/skills/{adia-ui-release → adia-release}/scripts/release-pack.mjs +13 -21
- package/skills/{adia-ui-release → adia-release}/scripts/tag-lockstep.mjs +5 -1
- package/skills/adia-site-docs/SKILL.md +68 -0
- package/skills/adia-site-docs/evals/audit-report.md +30 -0
- package/skills/adia-site-docs/evals/routing-corpus.json +176 -0
- package/skills/adia-site-docs/intent.md +72 -0
- package/agents/README.md +0 -209
- package/agents/author.md +0 -56
- package/agents/repo-steward.md +0 -56
- package/agents/spec-architect.md +0 -53
- package/agents/tech-lead.md +0 -57
- package/agents/verifier.md +0 -55
- package/bin/lib/audit-axes.mjs +0 -555
- package/bin/lib/dry-run-irreversible.mjs +0 -236
- package/bin/lib/run-skill-evals.mjs +0 -487
- package/bin/lib/teach-router.mjs +0 -250
- package/commands/adia-forge-a2ui.md +0 -10
- package/commands/adia-forge-author.md +0 -10
- package/commands/adia-forge-dogfood.md +0 -8
- package/commands/adia-forge-llm.md +0 -8
- package/commands/adia-forge-orient.md +0 -10
- package/commands/adia-forge-release.md +0 -8
- package/commands/adia-forge-review.md +0 -10
- package/references/shared/pev-rationale.md +0 -64
- package/references/shared/skill-conventions.md +0 -133
- package/skills/adia-ui-a2ui/CHANGELOG.md +0 -32
- package/skills/adia-ui-a2ui/SKILL.md +0 -243
- package/skills/adia-ui-a2ui/evals/adversarial-corpus.json +0 -75
- package/skills/adia-ui-a2ui/evals/teach-routing-cases.json +0 -100
- package/skills/adia-ui-a2ui/references/anti-patterns.md +0 -24
- package/skills/adia-ui-a2ui/references/chunk-authoring.md +0 -88
- package/skills/adia-ui-a2ui/references/corpus-discipline.md +0 -56
- package/skills/adia-ui-a2ui/references/eval-diagnostics.md +0 -127
- package/skills/adia-ui-a2ui/references/fragment-graph.md +0 -91
- package/skills/adia-ui-a2ui/references/mcp-pipeline-ops.md +0 -106
- package/skills/adia-ui-a2ui/references/mcp-tool-reference.md +0 -398
- package/skills/adia-ui-a2ui/references/pipeline-overview.md +0 -175
- package/skills/adia-ui-a2ui/references/semantic-fail-lifting.md +0 -120
- package/skills/adia-ui-a2ui/references/strategy-engines.md +0 -111
- package/skills/adia-ui-a2ui/references/teach-protocol.md +0 -220
- package/skills/adia-ui-a2ui/references/zettel-calibration.md +0 -93
- package/skills/adia-ui-a2ui/scripts/audit-a2ui-roster.mjs +0 -96
- package/skills/adia-ui-a2ui/scripts/teach-route.mjs +0 -157
- package/skills/adia-ui-a2ui/skill.json +0 -38
- package/skills/adia-ui-authoring/CHANGELOG.md +0 -32
- package/skills/adia-ui-authoring/SKILL.md +0 -256
- package/skills/adia-ui-authoring/assets/case-studies/admin-shell-decomposition.md +0 -101
- package/skills/adia-ui-authoring/assets/case-studies/maxtokens-32768-discovery.md +0 -109
- package/skills/adia-ui-authoring/assets/case-studies/theme-panel-promotion.md +0 -113
- package/skills/adia-ui-authoring/evals/adversarial-design-plan-gates.json +0 -138
- package/skills/adia-ui-authoring/evals/routing-corpus.json +0 -245
- package/skills/adia-ui-authoring/references/canonical-pattern-index.md +0 -179
- package/skills/adia-ui-authoring/references/common-gotchas.md +0 -93
- package/skills/adia-ui-authoring/references/composite-demo-protocol.md +0 -1084
- package/skills/adia-ui-authoring/references/teach-protocol.md +0 -428
- package/skills/adia-ui-authoring/scripts/audit-authoring-roster.mjs +0 -148
- package/skills/adia-ui-authoring/skill.json +0 -45
- package/skills/adia-ui-dogfood/CHANGELOG.md +0 -17
- package/skills/adia-ui-dogfood/README.md +0 -62
- package/skills/adia-ui-dogfood/SKILL.md +0 -866
- package/skills/adia-ui-dogfood/skill.json +0 -40
- package/skills/adia-ui-forge/SKILL.md +0 -88
- package/skills/adia-ui-forge/evals/routing-corpus.json +0 -30
- package/skills/adia-ui-gen-review/CHANGELOG.md +0 -108
- package/skills/adia-ui-gen-review/SKILL.md +0 -266
- package/skills/adia-ui-gen-review/references/loop-protocol.md +0 -712
- package/skills/adia-ui-gen-review/references/rubric-cosmetic.md +0 -144
- package/skills/adia-ui-gen-review/references/rubric-decompose.md +0 -117
- package/skills/adia-ui-gen-review/references/rubric-score.md +0 -249
- package/skills/adia-ui-gen-review/references/teach-protocol.md +0 -214
- package/skills/adia-ui-gen-review/skill.json +0 -23
- package/skills/adia-ui-llm/CHANGELOG.md +0 -25
- package/skills/adia-ui-llm/SKILL.md +0 -165
- package/skills/adia-ui-llm/evals/adversarial-corpus.json +0 -75
- package/skills/adia-ui-llm/evals/routing-corpus.json +0 -30
- package/skills/adia-ui-llm/evals/teach-routing-cases.json +0 -73
- package/skills/adia-ui-llm/references/teach-protocol.md +0 -78
- package/skills/adia-ui-llm/scripts/audit-llm-roster.mjs +0 -93
- package/skills/adia-ui-llm/scripts/teach-route.mjs +0 -119
- package/skills/adia-ui-llm/skill.json +0 -33
- package/skills/adia-ui-ops/CHANGELOG.md +0 -291
- package/skills/adia-ui-ops/SKILL.md +0 -401
- package/skills/adia-ui-ops/references/INDEX.md +0 -158
- package/skills/adia-ui-ops/references/audit-cadence.md +0 -263
- package/skills/adia-ui-ops/references/audit-patterns/archive-link-sweep.md +0 -96
- package/skills/adia-ui-ops/references/audit-patterns/audit-history-ledger.md +0 -162
- package/skills/adia-ui-ops/references/audit-patterns/browser-bundle-node-imports.md +0 -154
- package/skills/adia-ui-ops/references/audit-patterns/changelog-unreleased-bloat.md +0 -75
- package/skills/adia-ui-ops/references/audit-patterns/coverage-gaps.md +0 -187
- package/skills/adia-ui-ops/references/audit-patterns/entry-file-coverage.md +0 -122
- package/skills/adia-ui-ops/references/audit-patterns/format-hygiene.md +0 -217
- package/skills/adia-ui-ops/references/audit-patterns/lockstep-versioning.md +0 -113
- package/skills/adia-ui-ops/references/audit-patterns/memory-fragmentation.md +0 -180
- package/skills/adia-ui-ops/references/audit-patterns/orphan-detection.md +0 -202
- package/skills/adia-ui-ops/references/audit-patterns/pointer-validation.md +0 -180
- package/skills/adia-ui-ops/references/audit-patterns/redundancy-detection.md +0 -210
- package/skills/adia-ui-ops/references/audit-patterns/spec-dating-sweep.md +0 -91
- package/skills/adia-ui-ops/references/audit-patterns/stale-content.md +0 -182
- package/skills/adia-ui-ops/references/audit-patterns/staleness-tooling.md +0 -156
- package/skills/adia-ui-ops/references/audit-patterns/token-waste-detection.md +0 -196
- package/skills/adia-ui-ops/references/doc-types/adr-pattern.md +0 -210
- package/skills/adia-ui-ops/references/doc-types/architecture-md.md +0 -190
- package/skills/adia-ui-ops/references/doc-types/changelog.md +0 -183
- package/skills/adia-ui-ops/references/doc-types/decisions-log.md +0 -146
- package/skills/adia-ui-ops/references/doc-types/plan-roadmap.md +0 -182
- package/skills/adia-ui-ops/references/doc-types/postmortem-pattern.md +0 -206
- package/skills/adia-ui-ops/references/genres/prose-and-writing.md +0 -149
- package/skills/adia-ui-ops/references/guidance/context-budget.md +0 -137
- package/skills/adia-ui-ops/references/guidance/llm-doc-writing.md +0 -116
- package/skills/adia-ui-ops/references/guidance/reliability-dial.md +0 -186
- package/skills/adia-ui-ops/references/recipes/adr-introduction.md +0 -211
- package/skills/adia-ui-ops/references/recipes/audit-existing-repo.md +0 -234
- package/skills/adia-ui-ops/references/recipes/cold-start-harvest.md +0 -263
- package/skills/adia-ui-ops/references/recipes/concurrent-learnings-merge.md +0 -158
- package/skills/adia-ui-ops/references/recipes/continuous-learning-loop.md +0 -169
- package/skills/adia-ui-ops/references/recipes/external-reference-verification.md +0 -158
- package/skills/adia-ui-ops/references/recipes/findings-index-readout.md +0 -126
- package/skills/adia-ui-ops/references/recipes/greenfield-setup.md +0 -252
- package/skills/adia-ui-ops/references/recipes/harvest-repo-brain.md +0 -169
- package/skills/adia-ui-ops/references/recipes/import-repo-brain-harvest.md +0 -153
- package/skills/adia-ui-ops/references/recipes/memory-organization.md +0 -182
- package/skills/adia-ui-ops/references/recipes/recommend-then-validate.md +0 -199
- package/skills/adia-ui-ops/references/recipes/self-healing-hooks.md +0 -366
- package/skills/adia-ui-ops/references/recipes/skill-stewardship-loop.md +0 -113
- package/skills/adia-ui-ops/references/standards/agents-md-spec.md +0 -138
- package/skills/adia-ui-ops/references/standards/claude-md-convention.md +0 -123
- package/skills/adia-ui-ops/references/standards/cross-tool-matrix.md +0 -85
- package/skills/adia-ui-ops/references/standards/readme-conventions.md +0 -232
- package/skills/adia-ui-ops/references/teach-protocol.md +0 -215
- package/skills/adia-ui-ops/scripts/audit-ops-roster.mjs +0 -104
- package/skills/adia-ui-ops/skill.json +0 -65
- package/skills/adia-ui-release/CHANGELOG.md +0 -66
- package/skills/adia-ui-release/SKILL.md +0 -323
- package/skills/adia-ui-release/assets/case-studies/2026-05-20-batch-push-v0.6.14-v0.6.15.md +0 -144
- package/skills/adia-ui-release/assets/case-studies/2026-05-20-corpus-drift-remediation-v0.6.15.md +0 -155
- package/skills/adia-ui-release/assets/case-studies/2026-05-20-version-skip-correction-v0.6.12.md +0 -114
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-author-from-scratch-v0.6.18.md +0 -139
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-feedback37-retraction-v0.6.21.md +0 -124
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-fn1-enrichment-pass-v0.6.19.md +0 -125
- package/skills/adia-ui-release/assets/case-studies/2026-05-21-stale-test-detection-v0.6.20.md +0 -142
- package/skills/adia-ui-release/assets/case-studies/2026-05-23-freshness-gate-recovery-v0.6.32.md +0 -97
- package/skills/adia-ui-release/assets/case-studies/2026-05-26-catalog-drift-recurring-v0.6.40.md +0 -147
- package/skills/adia-ui-release/assets/templates/stub-changelog.template.md +0 -22
- package/skills/adia-ui-release/evals/evals.json +0 -164
- package/skills/adia-ui-release/references/changelog-discipline.md +0 -250
- package/skills/adia-ui-release/references/cycle-happy-path.md +0 -520
- package/skills/adia-ui-release/references/exe-deploy.md +0 -149
- package/skills/adia-ui-release/references/gates-catalog.md +0 -778
- package/skills/adia-ui-release/references/independent-package-release.md +0 -129
- package/skills/adia-ui-release/references/ledger-discipline.md +0 -232
- package/skills/adia-ui-release/references/migration-guide-authoring.md +0 -174
- package/skills/adia-ui-release/references/multi-agent-baseline.md +0 -207
- package/skills/adia-ui-release/references/notes-authoring.md +0 -212
- package/skills/adia-ui-release/references/recovery-paths.md +0 -262
- package/skills/adia-ui-release/references/rollup-notes.md +0 -208
- package/skills/adia-ui-release/references/teach-protocol.md +0 -468
- package/skills/adia-ui-release/scripts/audit-gate-roster.mjs +0 -196
- package/skills/adia-ui-release/scripts/make-ledger.mjs +0 -200
- package/skills/adia-ui-release/skill.json +0 -77
- package/skills/dogfood-sweep/CHANGELOG.md +0 -37
- package/skills/dogfood-sweep/README.md +0 -105
- package/skills/dogfood-sweep/SKILL.md +0 -1000
- package/skills/dogfood-sweep/analyze.mjs +0 -600
- package/skills/dogfood-sweep/skill.json +0 -31
- /package/skills/{adia-ui-authoring → adia-author}/references/api-contract.md +0 -0
- /package/skills/{adia-ui-release → adia-release}/scripts/assert-monorepo-root.mjs +0 -0
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
date: 2026-04-27
|
|
3
|
-
coverage: canonical
|
|
4
|
-
peers:
|
|
5
|
-
- self-healing-hooks.md
|
|
6
|
-
- audit-existing-repo.md
|
|
7
|
-
- ../guidance/reliability-dial.md
|
|
8
|
-
- ../audit-patterns/audit-history-ledger.md
|
|
9
|
-
primary_sources:
|
|
10
|
-
- Steve Yegge, "Welcome to Gas City" — multi-agent consensus pattern
|
|
11
|
-
- https://docs.anthropic.com/en/docs/claude-code/sub-agents — Claude Code subagent pattern
|
|
12
|
-
status: research-verified
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
# Recommend-then-validate (the two-agent fix pattern)
|
|
16
|
-
|
|
17
|
-
> _"You should never just have one coding agent managing infrastructure… you should always have at least two or three working together on a little crew. Any agent can go temporarily insane, at any time, and make a bad call."_
|
|
18
|
-
> — Steve Yegge, "Welcome to Gas City"
|
|
19
|
-
|
|
20
|
-
## What this delivers
|
|
21
|
-
|
|
22
|
-
A single agent's apply-mode pass is **one source of truth, no consensus**. If that agent hallucinates a fix, the bad fix lands. The recommend-then-validate pattern splits the work:
|
|
23
|
-
|
|
24
|
-
1. **Recommender** — reads the audit; proposes specific fixes; produces a structured fix plan.
|
|
25
|
-
2. **Validator** — receives the fix plan; dry-runs each fix against the trip-wires; vetoes any fix that would break an invariant; opens the PR with only the surviving fixes.
|
|
26
|
-
|
|
27
|
-
The validator is *not* a critic. It's an execution gate that runs the same trip-wires after a hypothetical fix and confirms they still pass. A fix that introduces a new violation gets rejected.
|
|
28
|
-
|
|
29
|
-
This pattern is **required for `strict` strictness** (per `../guidance/reliability-dial.md`) and **optional but recommended for `normal`** for any apply-mode pass touching >5 files.
|
|
30
|
-
|
|
31
|
-
## The fix-plan contract
|
|
32
|
-
|
|
33
|
-
The recommender emits a structured plan; the validator consumes it.
|
|
34
|
-
|
|
35
|
-
```yaml
|
|
36
|
-
# .brain/fix-plan-2026-04-27.yaml (transient; consumed then discarded)
|
|
37
|
-
strictness: normal
|
|
38
|
-
findings_addressed:
|
|
39
|
-
- id: DRIFT-CLAUDE-AGENTS
|
|
40
|
-
severity: critical
|
|
41
|
-
fixes:
|
|
42
|
-
- kind: symlink
|
|
43
|
-
target: CLAUDE.md
|
|
44
|
-
points_to: AGENTS.md
|
|
45
|
-
reason: "Eliminates drift; satisfies Promise 1."
|
|
46
|
-
- kind: edit
|
|
47
|
-
file: AGENTS.md
|
|
48
|
-
description: "Compress 'Conventions' from 80 to 30 lines (Promise 2)."
|
|
49
|
-
diff_preview: |
|
|
50
|
-
[diff body]
|
|
51
|
-
- kind: archive
|
|
52
|
-
file: docs/old-plan.md
|
|
53
|
-
move_to: .brain/archive/old-plan-2026-04-27.md
|
|
54
|
-
reason: "Orphan, last modified 2024-08-15."
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Each fix is *typed* (`symlink | edit | archive | create | delete`). The validator knows how to dry-run each kind.
|
|
58
|
-
|
|
59
|
-
## The validator's veto rules
|
|
60
|
-
|
|
61
|
-
After a hypothetical fix, the validator re-runs the relevant trip-wires:
|
|
62
|
-
|
|
63
|
-
| Fix kind | Validator checks |
|
|
64
|
-
|---|---|
|
|
65
|
-
| `symlink` | Symlink target exists; ownership/permissions correct |
|
|
66
|
-
| `edit` | Resulting file still <200 lines (entry files); frontmatter still valid; no new broken links introduced |
|
|
67
|
-
| `archive` | File is genuinely orphaned (per `../audit-patterns/orphan-detection.md`); not within active grace window |
|
|
68
|
-
| `create` | Path valid; doesn't conflict with existing file; YAML frontmatter present |
|
|
69
|
-
| `delete` | **Always vetoed.** Move to `.brain/archive/` instead. Hard rule, no overrides. |
|
|
70
|
-
|
|
71
|
-
If any veto fires, the fix is dropped from the plan and a finding is emitted: `VETO — <fix> rejected because <rule>`. The PR opens with the surviving fixes only.
|
|
72
|
-
|
|
73
|
-
## Implementation paths
|
|
74
|
-
|
|
75
|
-
### Path A — Sequential within Claude Code (simplest)
|
|
76
|
-
|
|
77
|
-
Use the Claude Code subagent pattern. Main agent acts as recommender; spawns a validator subagent via the Agent tool with a fresh context.
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
1. Main agent runs the audit, builds fix plan, writes .brain/fix-plan-*.yaml
|
|
81
|
-
2. Main agent spawns validator subagent: "Read .brain/fix-plan-*.yaml;
|
|
82
|
-
dry-run each fix; emit veto report."
|
|
83
|
-
3. Validator subagent returns veto list (fresh context — can't share rationalization)
|
|
84
|
-
4. Main agent removes vetoed fixes from plan; opens PR with remainder
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
The validator runs in fresh context, so it can't accidentally rationalize the recommender's earlier reasoning. Independent re-evaluation is the load-bearing property.
|
|
88
|
-
|
|
89
|
-
### Path B — Distributed via GitHub Actions
|
|
90
|
-
|
|
91
|
-
Two-job CI workflow. Job 1 (recommender) emits the fix plan as a workflow artifact. Job 2 (validator) downloads the artifact, dry-runs, opens the PR.
|
|
92
|
-
|
|
93
|
-
```yaml
|
|
94
|
-
# .github/workflows/repo-fixer-apply.yml
|
|
95
|
-
jobs:
|
|
96
|
-
recommend:
|
|
97
|
-
runs-on: ubuntu-latest
|
|
98
|
-
steps:
|
|
99
|
-
- uses: actions/checkout@v4
|
|
100
|
-
- run: bash scripts/audit.sh > /tmp/audit.json
|
|
101
|
-
- run: bash scripts/build-fix-plan.sh /tmp/audit.json > /tmp/fix-plan.yaml
|
|
102
|
-
- uses: actions/upload-artifact@v4
|
|
103
|
-
with: { name: fix-plan, path: /tmp/fix-plan.yaml }
|
|
104
|
-
|
|
105
|
-
validate:
|
|
106
|
-
needs: recommend
|
|
107
|
-
runs-on: ubuntu-latest
|
|
108
|
-
steps:
|
|
109
|
-
- uses: actions/checkout@v4
|
|
110
|
-
- uses: actions/download-artifact@v4
|
|
111
|
-
with: { name: fix-plan }
|
|
112
|
-
- run: bash scripts/validate-fix-plan.sh fix-plan.yaml > /tmp/vetoes.txt
|
|
113
|
-
- run: bash scripts/apply-survivors.sh fix-plan.yaml /tmp/vetoes.txt
|
|
114
|
-
- uses: peter-evans/create-pull-request@v6
|
|
115
|
-
with:
|
|
116
|
-
title: '[repo-fixer] Apply audited fixes'
|
|
117
|
-
body-path: /tmp/pr-body.md
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
Job isolation ensures the validator can't share state with the recommender — Yegge's insight in cleanest form.
|
|
121
|
-
|
|
122
|
-
## Iterating within a budget (autoresearch DNA)
|
|
123
|
-
|
|
124
|
-
> Inspired by Karpathy's [autoresearch](https://github.com/karpathy/autoresearch) — autonomous propose-evaluate-iterate within a fixed budget. Repo-fixer scopes the spirit, not the overnight unattended shape: bounded rounds, deterministic eval, every iteration logged to the audit history ledger.
|
|
125
|
-
|
|
126
|
-
The base pattern above is one round. For high-finding-count audits or `strict` strictness, that single round may leave fixes on the table — vetoed because of a *fixable* issue (e.g., a proposed AGENTS.md compression would still exceed 200 lines, but a tighter version wouldn't).
|
|
127
|
-
|
|
128
|
-
The iterate-within-budget extension: when the validator vetoes fixes, feed the veto reasons back to the recommender and let it re-propose. Bounded by an explicit budget.
|
|
129
|
-
|
|
130
|
-
### Configuration
|
|
131
|
-
|
|
132
|
-
`.brain/config.toml`:
|
|
133
|
-
|
|
134
|
-
```toml
|
|
135
|
-
[ops-repo.iteration]
|
|
136
|
-
enabled = false # default: false (opt-in)
|
|
137
|
-
max_rounds = 3 # hard cap; loop exits early if no new fixes survive
|
|
138
|
-
wall_clock_seconds = 300 # 5 minutes total across all rounds
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
Each round, the recommender receives:
|
|
142
|
-
|
|
143
|
-
1. The original audit findings (unchanged)
|
|
144
|
-
2. The previous round's veto report (new — the agent reads "your symlink fix was vetoed because the target wasn't valid; here's why")
|
|
145
|
-
3. The set of already-applied fixes from prior rounds (so it doesn't re-propose them)
|
|
146
|
-
|
|
147
|
-
Each round logs to the audit history ledger as a separate entry within the run.
|
|
148
|
-
|
|
149
|
-
### When iteration helps
|
|
150
|
-
|
|
151
|
-
| Scenario | Outcome with 1 round | Outcome with 3 rounds |
|
|
152
|
-
|---|---|---|
|
|
153
|
-
| Recommender proposes 200-line AGENTS.md compression that would exceed the budget | Vetoed; user gets a TODO | Round 2 produces a 150-line version that passes |
|
|
154
|
-
| Recommender suggests archiving a doc still in the 30-day grace window | Vetoed | Round 2 skips that doc; archives others |
|
|
155
|
-
| All fixes pass first-round validation | PR with N fixes | Same PR — loop exits early |
|
|
156
|
-
|
|
157
|
-
### When iteration doesn't help
|
|
158
|
-
|
|
159
|
-
- Single-finding fixes (no benefit beyond round 1)
|
|
160
|
-
- Vetoes that are fundamentally un-fixable (e.g., `delete-always-vetoed` — the rule will never let it through)
|
|
161
|
-
- `lax` strictness (over-engineered for the use case)
|
|
162
|
-
|
|
163
|
-
### Stop conditions
|
|
164
|
-
|
|
165
|
-
The loop terminates when ANY of:
|
|
166
|
-
|
|
167
|
-
1. All proposed fixes pass validation (early success)
|
|
168
|
-
2. Two consecutive rounds produce zero new survivors (convergence)
|
|
169
|
-
3. `max_rounds` reached
|
|
170
|
-
4. `wall_clock_seconds` exhausted
|
|
171
|
-
|
|
172
|
-
The PR opens with the union of surviving fixes across rounds, plus a final veto report listing what didn't survive.
|
|
173
|
-
|
|
174
|
-
### How autoresearch DNA maps in (and where it stops)
|
|
175
|
-
|
|
176
|
-
Autoresearch runs overnight, fully unattended, hill-climbing on a single file with a single metric. This loop runs in a single CI invocation, budgeted in minutes, human-reviewed via PR. We take *bounded propose-evaluate-iterate with a deterministic eval function* — we don't take overnight autonomy. Yegge alignment ("shepherds, not auto-pilots") stays intact.
|
|
177
|
-
|
|
178
|
-
## When NOT to use this pattern
|
|
179
|
-
|
|
180
|
-
- **Single-file fixes.** Symlinking CLAUDE.md once doesn't need two agents; the trip-wire itself is the validation.
|
|
181
|
-
- **`lax` strictness on prototypes.** Friction unjustified.
|
|
182
|
-
- **Repos with no production cost of doc breakage.** Solo side projects.
|
|
183
|
-
|
|
184
|
-
The pattern earns its keep on multi-file passes where one bad fix can cascade.
|
|
185
|
-
|
|
186
|
-
## Anti-patterns
|
|
187
|
-
|
|
188
|
-
- **Recommender and validator share context.** Defeats the purpose. Validator must run in fresh context (subagent or separate CI job).
|
|
189
|
-
- **Validator can edit the plan.** No. Validator only vetoes; the recommender's fixes are immutable inputs. Editing happens in the next round.
|
|
190
|
-
- **Skipping the veto report.** The PR body should include the full veto list — humans need to see what *wasn't* applied and why.
|
|
191
|
-
- **Auto-merging the PR.** No. The validator gate is necessary but not sufficient; humans still review and merge.
|
|
192
|
-
- **Three or more agents in parallel for the same plan.** Diminishing returns; coordination cost dominates after two. Yegge says "two or three" for *different problems*, not redundant validators on one problem.
|
|
193
|
-
|
|
194
|
-
## Cross-references
|
|
195
|
-
|
|
196
|
-
- Reliability dial (which `strictness` levels require this pattern): `../guidance/reliability-dial.md`
|
|
197
|
-
- Self-healing hooks (the trip-wires the validator runs): `self-healing-hooks.md`
|
|
198
|
-
- Audit recipe (the input to the recommender): `audit-existing-repo.md`
|
|
199
|
-
- Audit history (vetoes get recorded): `../audit-patterns/audit-history-ledger.md`
|
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
date: 2026-04-27
|
|
3
|
-
coverage: canonical
|
|
4
|
-
peers:
|
|
5
|
-
- continuous-learning-loop.md
|
|
6
|
-
- audit-existing-repo.md
|
|
7
|
-
- ../audit-patterns/staleness-tooling.md
|
|
8
|
-
- ../audit-patterns/redundancy-detection.md
|
|
9
|
-
primary_sources:
|
|
10
|
-
- https://github.com/lycheeverse/lychee-action
|
|
11
|
-
- https://github.com/typicode/husky
|
|
12
|
-
- https://pre-commit.com/
|
|
13
|
-
- https://docs.github.com/actions/using-workflows/triggering-a-workflow
|
|
14
|
-
- https://djw.fyi/portfolio/preventing-drift/
|
|
15
|
-
status: research-verified
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
# Self-healing hooks (delivers Promise 4)
|
|
19
|
-
|
|
20
|
-
> **The premise.** A repo without trip-wires can't honor the "self-healing" promise — it can only be clean today and rotten tomorrow. This recipe installs the hooks that catch breakage before it lands and the workflows that keep watch on a schedule.
|
|
21
|
-
|
|
22
|
-
## What "self-healing" means concretely
|
|
23
|
-
|
|
24
|
-
A self-healing repo:
|
|
25
|
-
|
|
26
|
-
1. **Refuses to merge PRs** that introduce drift between CLAUDE.md and AGENTS.md.
|
|
27
|
-
2. **Refuses to merge PRs** with broken intra-repo or external links in `.brain/` or `docs/`.
|
|
28
|
-
3. **Refuses commits** that bloat AGENTS.md / CLAUDE.md past the 200-line ceiling.
|
|
29
|
-
4. **Auto-archives** orphaned docs after a 30-day grace period.
|
|
30
|
-
5. **Surfaces stale content** weekly (scheduled CI), not on a someone-remembered-to-look basis.
|
|
31
|
-
6. **Captures decisions** at the moment of decision (ADR-on-architectural-change), not retroactively.
|
|
32
|
-
|
|
33
|
-
The first three are pre-commit / PR-time gates. The fourth is a scheduled workflow. The fifth is a scheduled audit. The sixth is a `continuous-learning-loop.md` flow.
|
|
34
|
-
|
|
35
|
-
## The hook stack
|
|
36
|
-
|
|
37
|
-
### Layer 1 — pre-commit hooks (local; catch problems before they leave the machine)
|
|
38
|
-
|
|
39
|
-
Use `pre-commit` (Python) or `husky` (Node). The skill recommends `pre-commit` for cross-language repos and `husky` for Node-monoculture.
|
|
40
|
-
|
|
41
|
-
#### pre-commit (`.pre-commit-config.yaml`)
|
|
42
|
-
|
|
43
|
-
```yaml
|
|
44
|
-
# .pre-commit-config.yaml
|
|
45
|
-
repos:
|
|
46
|
-
# Lint Markdown structure
|
|
47
|
-
- repo: https://github.com/igorshubovych/markdownlint-cli
|
|
48
|
-
rev: v0.42.0
|
|
49
|
-
hooks:
|
|
50
|
-
- id: markdownlint
|
|
51
|
-
files: '\.(md|MD)$'
|
|
52
|
-
|
|
53
|
-
# Repo-brain trip-wires (custom, local hooks)
|
|
54
|
-
- repo: local
|
|
55
|
-
hooks:
|
|
56
|
-
# Trip-wire 1: AGENTS.md / CLAUDE.md must not drift
|
|
57
|
-
- id: agents-claude-drift
|
|
58
|
-
name: AGENTS.md / CLAUDE.md must not have drifted prose
|
|
59
|
-
entry: bash -c 'bash scripts/check-agents-claude-drift.sh'
|
|
60
|
-
language: system
|
|
61
|
-
files: '^(AGENTS\.md|CLAUDE\.md)$'
|
|
62
|
-
pass_filenames: false
|
|
63
|
-
|
|
64
|
-
# Trip-wire 2: AGENTS.md / CLAUDE.md must stay <200 lines
|
|
65
|
-
- id: entry-file-length
|
|
66
|
-
name: Entry files <200 lines (warn at 150)
|
|
67
|
-
entry: bash -c 'for f in AGENTS.md CLAUDE.md; do if [ -f "$f" ] && [ ! -L "$f" ]; then n=$(wc -l <"$f"); if [ "$n" -gt 200 ]; then echo "ERROR: $f is $n lines (>200)"; exit 1; elif [ "$n" -gt 150 ]; then echo "WARN: $f is $n lines (>150)"; fi; fi; done'
|
|
68
|
-
language: system
|
|
69
|
-
pass_filenames: false
|
|
70
|
-
|
|
71
|
-
# Trip-wire 3: docs in .brain/ or docs/ must have a date
|
|
72
|
-
- id: doc-frontmatter-date
|
|
73
|
-
name: .brain/*.md and docs/*.md must have date frontmatter or "Last reviewed:" line
|
|
74
|
-
entry: bash -c 'bash scripts/check-doc-dates.sh'
|
|
75
|
-
language: system
|
|
76
|
-
files: '^(\.brain|docs)/.*\.md$'
|
|
77
|
-
pass_filenames: true
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
#### `scripts/check-agents-claude-drift.sh`
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
#!/usr/bin/env bash
|
|
84
|
-
# Trip-wire: AGENTS.md and CLAUDE.md must not have drifted prose.
|
|
85
|
-
# Pass cases:
|
|
86
|
-
# (a) CLAUDE.md is a symlink to AGENTS.md → identical content.
|
|
87
|
-
# (b) CLAUDE.md is a thin pointer (≤15 lines) referencing AGENTS.md.
|
|
88
|
-
# (c) AGENTS.md exists, CLAUDE.md does not.
|
|
89
|
-
# Fail: both exist as fat (>15 lines) divergent files.
|
|
90
|
-
|
|
91
|
-
set -euo pipefail
|
|
92
|
-
|
|
93
|
-
if [ ! -f AGENTS.md ] && [ ! -f CLAUDE.md ]; then
|
|
94
|
-
exit 0 # Neither exists; not this hook's problem
|
|
95
|
-
fi
|
|
96
|
-
|
|
97
|
-
if [ ! -f AGENTS.md ]; then
|
|
98
|
-
echo "ERROR: CLAUDE.md exists but AGENTS.md does not. Promote CLAUDE.md → AGENTS.md."
|
|
99
|
-
exit 1
|
|
100
|
-
fi
|
|
101
|
-
|
|
102
|
-
if [ ! -f CLAUDE.md ]; then
|
|
103
|
-
exit 0 # AGENTS.md only; fine
|
|
104
|
-
fi
|
|
105
|
-
|
|
106
|
-
# CLAUDE.md is a symlink? (clean)
|
|
107
|
-
if [ -L CLAUDE.md ]; then
|
|
108
|
-
target="$(readlink CLAUDE.md)"
|
|
109
|
-
if [ "$target" = "AGENTS.md" ]; then
|
|
110
|
-
exit 0
|
|
111
|
-
else
|
|
112
|
-
echo "ERROR: CLAUDE.md is a symlink to '$target', not AGENTS.md."
|
|
113
|
-
exit 1
|
|
114
|
-
fi
|
|
115
|
-
fi
|
|
116
|
-
|
|
117
|
-
# CLAUDE.md is thin? (clean)
|
|
118
|
-
claude_lines=$(wc -l < CLAUDE.md)
|
|
119
|
-
if [ "$claude_lines" -le 15 ]; then
|
|
120
|
-
if grep -q -i "AGENTS\.md" CLAUDE.md; then
|
|
121
|
-
exit 0
|
|
122
|
-
else
|
|
123
|
-
echo "ERROR: CLAUDE.md is short but doesn't reference AGENTS.md."
|
|
124
|
-
exit 1
|
|
125
|
-
fi
|
|
126
|
-
fi
|
|
127
|
-
|
|
128
|
-
# Both fat → drift risk.
|
|
129
|
-
echo "ERROR: Both AGENTS.md ($(wc -l <AGENTS.md) lines) and CLAUDE.md ($claude_lines lines) are fat."
|
|
130
|
-
echo " Demote one to a thin pointer or symlink. See ops-repo/standards/claude-md-convention.md."
|
|
131
|
-
exit 1
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
#### `scripts/check-doc-dates.sh`
|
|
135
|
-
|
|
136
|
-
```bash
|
|
137
|
-
#!/usr/bin/env bash
|
|
138
|
-
# Trip-wire: every .brain/*.md and docs/*.md must have a date.
|
|
139
|
-
set -euo pipefail
|
|
140
|
-
fail=0
|
|
141
|
-
for f in "$@"; do
|
|
142
|
-
if grep -qE '^date:[[:space:]]*[0-9]{4}-[0-9]{2}-[0-9]{2}' "$f"; then
|
|
143
|
-
continue # YAML frontmatter date OK
|
|
144
|
-
fi
|
|
145
|
-
if grep -qE '_Last reviewed:[[:space:]]*[0-9]{4}-[0-9]{2}-[0-9]{2}' "$f"; then
|
|
146
|
-
continue # Inline "Last reviewed:" line OK
|
|
147
|
-
fi
|
|
148
|
-
echo "ERROR: $f has no date frontmatter or 'Last reviewed:' line."
|
|
149
|
-
fail=1
|
|
150
|
-
done
|
|
151
|
-
exit $fail
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### Layer 2 — PR-time CI (catch problems before merge)
|
|
155
|
-
|
|
156
|
-
#### `.github/workflows/repo-brain-pr.yml`
|
|
157
|
-
|
|
158
|
-
```yaml
|
|
159
|
-
name: Repo-brain (PR)
|
|
160
|
-
|
|
161
|
-
on:
|
|
162
|
-
pull_request:
|
|
163
|
-
paths: ['**.md', '.brain/**', 'docs/**', 'AGENTS.md', 'CLAUDE.md', '.cursor/**', '.windsurfrules', '.github/copilot-instructions.md']
|
|
164
|
-
|
|
165
|
-
jobs:
|
|
166
|
-
links:
|
|
167
|
-
runs-on: ubuntu-latest
|
|
168
|
-
steps:
|
|
169
|
-
- uses: actions/checkout@v4
|
|
170
|
-
- name: Lychee link check
|
|
171
|
-
uses: lycheeverse/lychee-action@v2
|
|
172
|
-
with:
|
|
173
|
-
args: --cache --max-cache-age=1d --no-progress '.brain/**/*.md' 'docs/**/*.md' '*.md'
|
|
174
|
-
fail: true
|
|
175
|
-
|
|
176
|
-
drift-and-length:
|
|
177
|
-
runs-on: ubuntu-latest
|
|
178
|
-
steps:
|
|
179
|
-
- uses: actions/checkout@v4
|
|
180
|
-
- run: bash scripts/check-agents-claude-drift.sh
|
|
181
|
-
- run: bash scripts/check-entry-file-length.sh
|
|
182
|
-
|
|
183
|
-
doc-dates:
|
|
184
|
-
runs-on: ubuntu-latest
|
|
185
|
-
steps:
|
|
186
|
-
- uses: actions/checkout@v4
|
|
187
|
-
with: { fetch-depth: 0 }
|
|
188
|
-
- run: |
|
|
189
|
-
changed=$(git diff --name-only origin/${{ github.base_ref }}...HEAD -- '.brain/**/*.md' 'docs/**/*.md' || true)
|
|
190
|
-
if [ -n "$changed" ]; then
|
|
191
|
-
bash scripts/check-doc-dates.sh $changed
|
|
192
|
-
fi
|
|
193
|
-
|
|
194
|
-
llm-doc-drift:
|
|
195
|
-
if: ${{ vars.LLM_DOC_DRIFT_ENABLED == 'true' }}
|
|
196
|
-
runs-on: ubuntu-latest
|
|
197
|
-
steps:
|
|
198
|
-
- uses: actions/checkout@v4
|
|
199
|
-
with: { fetch-depth: 0 }
|
|
200
|
-
- name: Ask LLM if code diff requires doc updates
|
|
201
|
-
env:
|
|
202
|
-
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
203
|
-
run: bash scripts/llm-doc-drift-check.sh
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
The `llm-doc-drift` job is opt-in (gated on `vars.LLM_DOC_DRIFT_ENABLED`) — costs API calls per PR. Worth it for high-traffic repos; overkill for hobby projects.
|
|
207
|
-
|
|
208
|
-
### Layer 3 — scheduled CI (find problems no commit triggered)
|
|
209
|
-
|
|
210
|
-
#### `.github/workflows/repo-brain-weekly.yml`
|
|
211
|
-
|
|
212
|
-
```yaml
|
|
213
|
-
name: Repo-brain (weekly audit)
|
|
214
|
-
|
|
215
|
-
on:
|
|
216
|
-
schedule:
|
|
217
|
-
- cron: '0 13 * * 1' # Mondays 13:00 UTC
|
|
218
|
-
workflow_dispatch:
|
|
219
|
-
|
|
220
|
-
jobs:
|
|
221
|
-
full-audit:
|
|
222
|
-
runs-on: ubuntu-latest
|
|
223
|
-
steps:
|
|
224
|
-
- uses: actions/checkout@v4
|
|
225
|
-
with: { fetch-depth: 0 }
|
|
226
|
-
|
|
227
|
-
- name: External link check (full)
|
|
228
|
-
uses: lycheeverse/lychee-action@v2
|
|
229
|
-
with:
|
|
230
|
-
args: --no-progress '.brain/**/*.md' 'docs/**/*.md' '*.md'
|
|
231
|
-
fail: false # Don't fail; report
|
|
232
|
-
|
|
233
|
-
- name: Stale-doc detection (mtime + frontmatter)
|
|
234
|
-
run: bash scripts/find-stale-docs.sh > stale-report.md
|
|
235
|
-
|
|
236
|
-
- name: Orphan detection
|
|
237
|
-
run: bash scripts/find-orphan-docs.sh > orphan-report.md
|
|
238
|
-
|
|
239
|
-
- name: Open issue if findings
|
|
240
|
-
if: always()
|
|
241
|
-
uses: actions/github-script@v7
|
|
242
|
-
with:
|
|
243
|
-
script: |
|
|
244
|
-
const fs = require('fs');
|
|
245
|
-
const stale = fs.readFileSync('stale-report.md', 'utf8');
|
|
246
|
-
const orphans = fs.readFileSync('orphan-report.md', 'utf8');
|
|
247
|
-
if (stale.trim() || orphans.trim()) {
|
|
248
|
-
await github.rest.issues.create({
|
|
249
|
-
owner: context.repo.owner,
|
|
250
|
-
repo: context.repo.repo,
|
|
251
|
-
title: `[ops-repo] Weekly audit findings — ${new Date().toISOString().slice(0,10)}`,
|
|
252
|
-
body: `## Stale docs\n\n${stale}\n\n## Orphans\n\n${orphans}`,
|
|
253
|
-
labels: ['docs', 'ops-repo']
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
### Layer 4 — auto-archive (the orphan grace-period flow)
|
|
259
|
-
|
|
260
|
-
#### `scripts/find-orphan-docs.sh`
|
|
261
|
-
|
|
262
|
-
```bash
|
|
263
|
-
#!/usr/bin/env bash
|
|
264
|
-
# Find docs in .brain/ or docs/ not referenced by any entry file or other doc.
|
|
265
|
-
set -euo pipefail
|
|
266
|
-
all_docs=$(find .brain docs -type f -name '*.md' 2>/dev/null)
|
|
267
|
-
referenced=$(
|
|
268
|
-
cat AGENTS.md CLAUDE.md README.md .brain/**/*.md docs/**/*.md 2>/dev/null \
|
|
269
|
-
| grep -oE '\[[^]]+\]\(([^)]+)\)' \
|
|
270
|
-
| grep -oE '\(([^)]+)\)' \
|
|
271
|
-
| tr -d '()' \
|
|
272
|
-
| sort -u
|
|
273
|
-
)
|
|
274
|
-
for f in $all_docs; do
|
|
275
|
-
base=$(basename "$f")
|
|
276
|
-
if ! echo "$referenced" | grep -q -F "$base"; then
|
|
277
|
-
# Orphan candidate.
|
|
278
|
-
last_modified=$(git log -1 --format=%cs -- "$f")
|
|
279
|
-
echo "- $f (last modified: $last_modified)"
|
|
280
|
-
fi
|
|
281
|
-
done
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
#### `.github/workflows/repo-brain-auto-archive.yml`
|
|
285
|
-
|
|
286
|
-
```yaml
|
|
287
|
-
name: Repo-brain (auto-archive orphans after 30-day grace)
|
|
288
|
-
on:
|
|
289
|
-
schedule:
|
|
290
|
-
- cron: '0 13 * * 1' # Mondays
|
|
291
|
-
workflow_dispatch:
|
|
292
|
-
|
|
293
|
-
jobs:
|
|
294
|
-
archive:
|
|
295
|
-
runs-on: ubuntu-latest
|
|
296
|
-
steps:
|
|
297
|
-
- uses: actions/checkout@v4
|
|
298
|
-
with: { fetch-depth: 0 }
|
|
299
|
-
- name: Move stale orphans to .brain/archive/
|
|
300
|
-
run: |
|
|
301
|
-
# An orphan unmodified for 30+ days AND not in /archive/ → archive it.
|
|
302
|
-
while IFS= read -r line; do
|
|
303
|
-
[[ -z "$line" ]] && continue
|
|
304
|
-
f=$(echo "$line" | cut -d' ' -f2)
|
|
305
|
-
[[ "$f" == .brain/archive/* ]] && continue
|
|
306
|
-
[[ "$f" == docs/archive/* ]] && continue
|
|
307
|
-
mtime=$(git log -1 --format=%ct -- "$f")
|
|
308
|
-
now=$(date +%s)
|
|
309
|
-
age_days=$(( (now - mtime) / 86400 ))
|
|
310
|
-
if [ "$age_days" -gt 30 ]; then
|
|
311
|
-
mkdir -p .brain/archive
|
|
312
|
-
git mv "$f" ".brain/archive/$(basename "$f")"
|
|
313
|
-
echo "Archived: $f (orphan for ${age_days}d)"
|
|
314
|
-
fi
|
|
315
|
-
done < <(bash scripts/find-orphan-docs.sh)
|
|
316
|
-
- name: Open PR
|
|
317
|
-
uses: peter-evans/create-pull-request@v6
|
|
318
|
-
with:
|
|
319
|
-
base: main # see the gotcha below — required for tag-push triggers
|
|
320
|
-
title: '[ops-repo] Auto-archive stale orphan docs'
|
|
321
|
-
body: 'Auto-archived orphan docs untouched for 30+ days. Review and merge or revert.'
|
|
322
|
-
branch: ops-repo/auto-archive
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
The PR step is critical — **never silently delete or move docs**. Always open a PR so a human can review.
|
|
326
|
-
|
|
327
|
-
### Gotcha — `peter-evans/create-pull-request` needs `base: main` on tag-push
|
|
328
|
-
|
|
329
|
-
If your workflow also triggers on tag pushes (e.g., a build-log harvest that fires on every release tag), the GitHub Actions runner checks out the *tag* — which is a detached HEAD, not a branch. Without an explicit `base` input, `create-pull-request` exits with:
|
|
330
|
-
|
|
331
|
-
```
|
|
332
|
-
##[error]When the repository is checked out on a commit instead of a branch,
|
|
333
|
-
the 'base' input must be supplied.
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
**Symptom**: every tag-push run of the workflow fails at the PR-opening step. Cron and `workflow_dispatch` runs (which check out the branch) succeed; tag-push runs fail. The audit ledger drops entries silently — the harvester writes the JSON, but the PR never opens, so the entry never lands on `main`.
|
|
337
|
-
|
|
338
|
-
**Fix**: always set `base: main` (or your default branch). It's a no-op on cron / dispatch runs (the action would auto-detect `main` anyway) and load-bearing on tag-push runs.
|
|
339
|
-
|
|
340
|
-
Observed in the wild on 2026-04-28 — a build-log workflow at `adiahealth/gen-ui-kit` failed for 8 consecutive tag-push runs because the action wouldn't open the PR. The cron path worked but the entry sat in an unmerged PR (`ops-repo/build-log` branch) for 2 days, so the ledger appeared frozen at the last manually-merged entry. The fix is one line.
|
|
341
|
-
|
|
342
|
-
## What the audit verifies
|
|
343
|
-
|
|
344
|
-
When `ops-repo` audits a repo, the self-healing check looks for:
|
|
345
|
-
|
|
346
|
-
1. ✅ `.pre-commit-config.yaml` exists OR `.husky/` has equivalent hooks.
|
|
347
|
-
2. ✅ The `agents-claude-drift`, `entry-file-length`, `doc-frontmatter-date` hooks are wired.
|
|
348
|
-
3. ✅ `.github/workflows/repo-brain-pr.yml` (or equivalent) exists and includes lychee.
|
|
349
|
-
4. ✅ `.github/workflows/repo-brain-weekly.yml` (or equivalent scheduled audit) exists.
|
|
350
|
-
5. ✅ `scripts/check-agents-claude-drift.sh` and the other helper scripts exist.
|
|
351
|
-
|
|
352
|
-
If any are missing, the audit emits a `MISSING TRIP-WIRE` finding with severity = high (because the promise of self-healing isn't being delivered).
|
|
353
|
-
|
|
354
|
-
## Common anti-patterns
|
|
355
|
-
|
|
356
|
-
- **Hooks defined but not installed** — `.pre-commit-config.yaml` exists but no one ran `pre-commit install`. The audit cannot detect installation; this is a `setup` step in `recipes/greenfield-setup.md`.
|
|
357
|
-
- **Auto-archive without PR step** — silently moving files breaks links. Always go through PR.
|
|
358
|
-
- **Lychee with `fail: false` everywhere** — defeats the gate. Use `fail: true` on PR; `fail: false` only on scheduled audits where issue-opening is the action.
|
|
359
|
-
- **No grace period on orphans** — files get archived on the first scan after they go orphaned. 30 days is the recommended floor.
|
|
360
|
-
|
|
361
|
-
## Cross-references
|
|
362
|
-
|
|
363
|
-
- Continuous-learning loop (Promise 5): `continuous-learning-loop.md`
|
|
364
|
-
- Staleness tooling deep dive: `../audit-patterns/staleness-tooling.md`
|
|
365
|
-
- Redundancy detection: `../audit-patterns/redundancy-detection.md`
|
|
366
|
-
- Full audit recipe: `audit-existing-repo.md`
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
# Skill stewardship loop
|
|
2
|
-
|
|
3
|
-
The continuously-learning loop for procedural memory (skills) — the
|
|
4
|
-
analog of `harvest ops-repo` for the doc surface.
|
|
5
|
-
|
|
6
|
-
**Authored:** 2026-05-02 — implements Step 2 of the ops-repo v2.0
|
|
7
|
-
skill-stewardship evolution. Pairs with `scripts/skills/audit-skills.mjs`
|
|
8
|
-
+ `scripts/skills/draft-skill.mjs` + `scripts/skills/check-skill-frontmatter.mjs`.
|
|
9
|
-
|
|
10
|
-
## The cadence
|
|
11
|
-
|
|
12
|
-
Run `npm run audit:skills` at three triggers:
|
|
13
|
-
|
|
14
|
-
1. **Session-end** of any major work (release cut, multi-day arc,
|
|
15
|
-
postmortem). Surfaces candidates from procedures the session walked.
|
|
16
|
-
2. **Quarterly** as part of the `/ops-repo` audit. Catches accumulated
|
|
17
|
-
drift — stale refs, redundancy, low-utility skills.
|
|
18
|
-
3. **On-demand** when the user asks "is anything stale?" or "what
|
|
19
|
-
skills should we have?".
|
|
20
|
-
|
|
21
|
-
Each run produces 0–N findings. Triage by severity:
|
|
22
|
-
|
|
23
|
-
- **Errors** (currently none from `audit:skills`; `check:skills` produces
|
|
24
|
-
errors for missing frontmatter).
|
|
25
|
-
- **Warns** — stale refs, description redundancy. Fix immediately or
|
|
26
|
-
document as deferred.
|
|
27
|
-
- **Info** — procedure-recurrence candidates, graduation gaps,
|
|
28
|
-
description-divergence hints. Review; promote to drafts via
|
|
29
|
-
`npm run draft:skill <name>` when appropriate.
|
|
30
|
-
|
|
31
|
-
## The 6 detection signals (recap)
|
|
32
|
-
|
|
33
|
-
| # | Signal | Threshold | What it surfaces |
|
|
34
|
-
|---|---|---|---|
|
|
35
|
-
| 1 | Pattern recurrence in journals | ≥ 2 sessions | Procedures walked enough to deserve a skill |
|
|
36
|
-
| 2 | Graduations without skills | row mentions script but no skill | Permanent infrastructure that lacks procedural skill capture |
|
|
37
|
-
| 3 | Memory citation count | ≥ 3 citations | Memory entries hot enough to warrant skill promotion |
|
|
38
|
-
| 4 | Stale path/tag refs in SKILL.md | path doesn't resolve | Skills referencing renamed code |
|
|
39
|
-
| 5 | Description-vs-body divergence | body churn ≥ 100 lines | Skills whose body has evolved beyond the description |
|
|
40
|
-
| 6 | Pairwise description similarity | Jaccard ≥ 0.6 | Likely-redundant skill pairs |
|
|
41
|
-
|
|
42
|
-
Thresholds tunable via `.brain/config.toml` (when implemented; today
|
|
43
|
-
they're hardcoded in `audit-skills.mjs`).
|
|
44
|
-
|
|
45
|
-
## The triage flow
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
audit-skills (read-only)
|
|
49
|
-
│
|
|
50
|
-
▼
|
|
51
|
-
finding cluster
|
|
52
|
-
│
|
|
53
|
-
├─→ stale-skill-ref ──────→ iterate skill --update (fix paths)
|
|
54
|
-
│ (or: just edit SKILL.md directly)
|
|
55
|
-
│
|
|
56
|
-
├─→ description-similarity ──→ iterate skill --merge OR
|
|
57
|
-
│ edit descriptions to differentiate
|
|
58
|
-
│
|
|
59
|
-
├─→ procedure-recurrence ──→ draft-skill <name> --journal-section ...
|
|
60
|
-
│ (operator reviews + commits)
|
|
61
|
-
│
|
|
62
|
-
├─→ graduation-without-skill → draft-skill <name> --audit-finding ...
|
|
63
|
-
│ (or: skip if mechanical infra is enough)
|
|
64
|
-
│
|
|
65
|
-
└─→ description-divergence-hint ──→ review SKILL.md description vs body;
|
|
66
|
-
edit description if stale
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Anti-patterns
|
|
70
|
-
|
|
71
|
-
- **Acting on every info finding.** Info-level signals are advisory.
|
|
72
|
-
Procedure-recurrence in journals doesn't *always* mean a skill is
|
|
73
|
-
warranted — sometimes the recurring section is "Verification" which
|
|
74
|
-
is just session-end discipline, not a procedure. Triage before
|
|
75
|
-
promoting.
|
|
76
|
-
|
|
77
|
-
- **Auto-archiving stale skills.** `audit-skills` doesn't have an
|
|
78
|
-
`archive` mode for the same reason `ops-repo` doesn't auto-delete
|
|
79
|
-
orphan docs: a stale skill might just need an `iterate skill --update`
|
|
80
|
-
pass, not deletion. Archive only after explicit superseded-by
|
|
81
|
-
designation.
|
|
82
|
-
|
|
83
|
-
- **Filling out the skeleton in one pass.** `draft-skill` produces a
|
|
84
|
-
TODO-heavy SKILL.md. The skeleton lays the canvas; **synthesis is a
|
|
85
|
-
separate pass**, ideally invoking `meta-skill` /
|
|
86
|
-
`meta-expert-author` against the skeleton. Don't ship a draft as
|
|
87
|
-
if it were a finished skill — `check:skills` catches the
|
|
88
|
-
description-too-short and trigger-phrases-thin cases, but only after
|
|
89
|
-
you ask CI to validate.
|
|
90
|
-
|
|
91
|
-
- **Treating user-level skills as in scope.** This audit walks
|
|
92
|
-
`.agents/skills/` (project-local) only. User-level skills at
|
|
93
|
-
`~/.claude/skills/` (or `~/.pi/agent/skills/` for Pi) are managed by a separate cadence — they travel
|
|
94
|
-
across projects and shouldn't be governed by any single project's
|
|
95
|
-
audit. Run a separate user-level audit quarterly if needed.
|
|
96
|
-
|
|
97
|
-
## Pairs with
|
|
98
|
-
|
|
99
|
-
- `lockstep-release` — every coordinated cut graduates infrastructure;
|
|
100
|
-
the post-publish admin should include `audit:skills` to capture any
|
|
101
|
-
procedures the cut walked.
|
|
102
|
-
- `stale-audit` — sibling sweep for the doc surface.
|
|
103
|
-
- `ops-postmortem` — postmortems often surface graduation
|
|
104
|
-
candidates that map to skills.
|
|
105
|
-
- `ops-memory` — when memory entries are superseded by
|
|
106
|
-
skills, the entry's description should flag the supersession.
|
|
107
|
-
|
|
108
|
-
## Future evolution
|
|
109
|
-
|
|
110
|
-
- **Telemetry-based utility detection.** When the harness logs `Skill({skill: X})` invocations, low-utility skills (zero invocations across N sessions despite matching prompts) become detectable. Today only the heuristic divergence-hint exists.
|
|
111
|
-
- **Description-vs-body diff.** Today's body-churn-since-description-edit is approximate. A real diff would track which lines of the description haven't been touched since the body changes.
|
|
112
|
-
- **Cross-skill pairs-with graph audit.** When skill A says "pairs with B" but B doesn't say "pairs with A", the graph is asymmetric. An audit signal could flag.
|
|
113
|
-
- **Skill lifecycle states in frontmatter.** Adding `status: candidate | draft | active | stale | superseded | archived` would let the audit transition skills explicitly through the graph.
|