Files
holocron/SIMPLIFICATION-AUDIT.md
Defame1297 e647f14535 chore: delete the check-manifests pre-commit hook
Six pre-push hooks were validating overlapping sets of the same
manifests. check-manifests (marketplace.json/plugin.json path checks)
is redundant with validate-plugins (claude plugin validate) and
apm-pack-check-clean, which already cover the same ground.

Deletes the check-manifests hook entry, scripts/check-manifests.sh
(282 lines), and tests/test-check-manifests.sh (771 lines).
scripts/lib/marketplace-plugins.sh is kept — it is still sourced by
sync-plugin-content.sh. Updates the now-stale check-manifests.sh
mentions and hook counts in README.md and docs/spec/gates.md.

The apm-audit-ci and apm-marketplace-check hooks named in the same
finding are left untouched — the audit flags them as needing a
separate decision.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
2026-09-12 19:59:33 +00:00

32 KiB
Raw Blame History

Simplification audit

Date: 2026-09-10. Read-only analysis; nothing has been changed. Purpose: a hand-off for deciding what to remove, merge, and shrink. Findings are ranked by payoff within each area; effort is S/M/L. Claims were independently re-verified against the repo by a clean reviewer; corrections have been applied.

Assumptions agreed before analysis: anything is on the table, Claude Code and Copilot CLI both stay supported, findings are ranked with effort.

Counting convention: line counts are hand-edited .apm/ source unless marked "incl. mirror". Every .apm/ file has a byte-identical generated copy at the plugin root, so plugin cuts count double in the repo total.

1. The shape of the problem

Measure Value
Tracked files / lines 820 / 102,000
Lines in plugins/ 70,600 (69% of repo)
Of which the 39 SKILL.md files a model actually loads ~2,600 lines (under 4% of plugin lines)
Generated flat mirror files (byte copies of .apm/) 263 files, ~22,000 lines
docs/research/ vendored inside plugins ~19,000 lines, nothing executable reads it
Repo-level docs/research/ + docs/notes/ 4,500 lines, 47% of all prose words, 6 of 11 research files linked only from each other
Enforcement: hook entries in .pre-commit-config.yaml / pre-push hooks 33 / 14
Enforcement: tests/*.sh + runners + scripts/ 12,400 + 475 + 4,500 lines
Validator scripts inside kyberforge (+ their bats tests) 6,800 + 5,300 lines
Preload tax (39 skill names + descriptions) 10,987 chars, ~2,750 tokens per session
Commits since 2026-05-10 / share touching hook, test, gate, vale, or sync 447 / ~25%

The pattern across every area is the same: the payload (skill bodies, rules, decisions) is small and the scaffolding around it (mirrors, research dumps, sync gates, tests of tests, justification prose) is 10 to 30 times larger. A quarter of all commits have gone into maintaining the scaffolding.

2. Measured baseline: hooks and tests

Measured on this machine, clean tree, all hooks passing. pre-commit run --all-files per stage.

Gate Wall time
Full pre-push stage (everything below, sequential) ~5 min 10 s
run-tests (26 bash suites + 351 bats tests) 276 s
apm-audit-ci (7 manifests) 12.2 s
validate-plugins (6 × claude plugin validate) 4.9 s
check-plugin-content-sync 4.5 s
apm-pack-check-clean 3.1 s
Other 9 pre-push hooks combined 7.6 s
Full pre-commit stage, all files 18.2 s

run-tests is 90% of the wall time. Every push pays it in full: the runner has no change detection and the config sets always_run: true. apm-audit-ci is the second-slowest hook; per its own comment block its earlier description overclaimed, and what it verifies today is that seven manifests parse and the lockfile exists.

Where the 276 s goes (each suite run alone, sequential):

Suite Time Note
test-sync-plugin-content.sh 83 s 14 temp trees, 2 git init, repeated apm pack
all 351 bats tests (10 files, kyberforge and core validators) 64 s mostly validate.sh / validate-provenance.sh fixtures
test-adr0020-differential.sh 29 s 12 assertions; re-runs two validators over the live corpus and a fixture tree
test-check-vale-style-sync.sh 25 s guards a byte-identical copy
test-vale-wrap.sh 14 s
test-adr0020-frontmatter.sh + -targets.sh 25 s
Remaining 20 suites 36 s 12 of them run in under 2 s each

Five suites account for 215 s of 276 s. Three of those five (sync-plugin-content, vale-style-sync, adr0020-differential) test tooling that findings 2, 7, and 14 propose to delete or shrink, so the fastest path to a quick pre-push is removing the duplication those tests guard rather than optimising the tests.

3. Enforcement layer: hooks, tests, scripts

This is the area you named as hardest to understand and slowest. Root cause: most pre-push hooks exist to keep two copies of something in sync, or to re-validate what another hook already validates.

  1. Six hooks validate overlapping sets of the same manifests. check-manifests, validate-plugins, validate-marketplace, apm-pack-check-clean, apm-marketplace-check, apm-audit-ci. Keep the two claude plugin validate hooks plus apm-pack-check-clean. Delete check-manifests (282 lines + 771 test lines; its lib/marketplace-plugins.sh stays because sync-plugin-content.sh sources it). apm-audit-ci spends 12 s confirming that manifests apm pack already parses do parse; drop or keep on that basis. Move the network-dependent apm-marketplace-check to a release checklist. Effort S.

    Done (2026-09-12): see commit 9051d14 on docs/simplification-audit. Deleted the check-manifests pre-commit hook entry, scripts/check-manifests.sh (282 lines), and tests/test-check-manifests.sh (771 lines); kept scripts/lib/marketplace-plugins.sh, still sourced by sync-plugin-content.sh. Updated the now-stale check-manifests.sh mentions in README.md and docs/spec/gates.md (hook table row and hook counts). The apm-audit-ci and apm-marketplace-check decisions in this finding remain open — out of scope for this change.

  2. Four "keep two copies in sync" gates: 1,100 script lines + 1,600 test lines. Each one is a symptom of duplication that could be removed instead of guarded:

    • check-vale-style-sync: 413 lines + 798 test lines guarding a byte-identical 526-line vale-wrap.sh and style directory copied between skill-audit and agent-audit. About 350 of its lines run Vale glob probes against the hook file patterns. Disappears if the two audit skills merge (finding 14); the probes belong in test-vale-wrap.sh.
    • check-scope-walkup-sync: 365 lines cross-checking four independent ports of the same package-root walk-up. Disappears if the ports share one script or the skills merge.
    • check-marketplace-mirror-sync: guards .github/plugin/marketplace.json. The script header calls it Copilot's legacy convention path and says Copilot also accepts the Claude path; the vendored Copilot docs list it as primary. Verify against current Copilot CLI before deleting hook, script, test, and mirror file.
    • check-executables-allow-sync: 474 lines to assert one string equals kyberforge's version. A six-line grep, or drop it (the failure mode is visible and recoverable). Effort S each, M for the walk-up.
  3. Tests of the test harness: 1,090 lines testing 475 lines. test-run-tests.sh and test-run-bats.sh defend "green either way" holes that exist only because the runners hand-roll TAP parsing and set-equality checks. Replace both runners with about 40 lines (bats -r plugins plus a parallel find | xargs over test-*.sh) and delete the meta-tests. lib/batch-run.sh stays; sync-plugin-content.sh sources it. Effort M.

  4. skill-frontmatter is a 62-line bash script inlined in YAML with its own 366-line test. skill-size-check.sh already parses the same frontmatter with PyYAML. Fold it in (about 15 Python lines), delete the inline hook, its test, and the 79 lines in gates.md arguing for the split. Effort S.

  5. skill-size-check.sh has six test files totalling 3,589 lines for one 1,497-line script, split by ADR section rather than behaviour. test-adr0020-differential.sh is 452 lines for 12 assertions. Merge to two files. Effort M.

  6. Prose-grep tests. test-governance-layer.sh and test-instructions-and-docs.sh (583 lines) grep markdown for phrases, including a one-shot "issue 0015 refactor incomplete" assertion made permanent and an assertion that docs/notes/ exists. Delete both. check-apm-agents-valid.sh (161 + 264 test lines) is a loop plus fail-closed guards around validate.sh; it folds into the merged audit skill's own tests (finding 14). Effort S.

  7. check-plugin-content-sync.sh is 813 lines wrapping apm pack, with a 1,291-line test. The mirror itself must stay (Claude Code marketplace installs need flat directories), and the script does real work a bare git diff would lose: it strips tests/ from the mirror, regenerates both plugin.json files with mcpServers reinjected, and packs into a scratch copy so --check never mutates. Even so, 2,100 lines for that is disproportionate; target a third. Effort M.

  8. docs/spec/gates.md (1,048 lines) is roughly 15% "what is enforced" and 85% post-mortems of defects already fixed and pinned by tests. The 60-line hook table is the useful part. Target 200 lines. The same applies to the 106 comment lines in .pre-commit-config.yaml and to scripts/, where 8 of 15 files are 40 to 60% comments. Effort M.

Proposed target. Pre-push 14 hooks to 6: run-tests, validate-plugins, validate-marketplace, apm-pack-check-clean, check-plugin-content-sync, check-release-needed. Pre-commit stays roughly as is minus skill-frontmatter, and minus check-ast once finding 9 removes the only .py files. Tests 26 files to about 10 (12,400 to about 5,000 lines). Keep bats and its three submodules; the 351 bats tests ship inside plugins and are the right tool there. Do not port the bash suites to bats; delete them instead.

4. Plugins

The shared pattern: per-skill README.md files no model reads, a docs/research/ dump per plugin, a sources.md provenance chain with its own validator, and reference files that restate man pages.

4.1 Cross-plugin (apply everywhere)

  1. Delete docs/research/ from every plugin (~19,000 lines). kyberforge's alone is 14,143 lines, 32% of the plugin, and about 8,900 of those are vendored third-party content (Anthropic skill-creator including a 1,325-line viewer.html and ten .py files, obra/superpowers, mattpocock). The rest is copied tool documentation. The gitea references explicitly say the research doc "has a known history of drifting from the deployed server". Every apm.yml uses includes: auto; whether the directory ships to consumers needs one check. Keep upstream URLs in one line per plugin README; git history keeps the rest. Check obra/superpowers licence if anything is retained. Goes together with finding 11: 32 sources.md files carry "Research doc" paths into these directories. Effort S.

    Decision (2026-09-12): Keep. docs/research/ is retained on purpose — it's read by agents doing work sourced from those docs. Not proceeding.

  2. Delete per-skill README.md and references/README.md (48 files, 1,574 lines). They restate the SKILL.md in narrative form. The pre-commit config itself notes a skill README "is consumer-facing prose that no agent ever loads". Keep one plugin-level README with one line per skill. Requires dropping the README criterion in skill-audit/references/file-structure.md and the README step in new-skill.sh. Effort S.

Done (2026-09-12): see commit edcc57c on docs/simplification-audit. Deleted the 48 per-skill/reference READMEs plus 2 scaffold templates; dropped the README criterion from skill-audit's file-structure.md and finding-criteria.md and the README-generation step from new-skill.sh; updated new-skill.bats to match. Plugin-root READMEs were kept, not part of this finding.

  1. Drop the provenance chain: sources.md, source_keys frontmatter, validate-provenance.sh. 32 plugin and skill sources.md files (about 1,300 lines) plus 9 research indexes, 216 source files with source_keys, two copies of the validator (1,198 and 632 lines) with ten checks, and 125 bats tests exist to track which upstream informed which file. Git blame and a URL in the README do the same job. This is more code than the content it tracks. Effort M (touches skill-audit, both validator copies, two repo tests, and every skill's frontmatter).

  2. Strip ADR and changelog narration from model-facing files. ADR-0020 is cited in 3 of 7 kyberforge SKILL.md files and 16 references; ADR-0023 is cited inline 21 times in the git plugin. Examples: "was the old house rule and ADR-0020 deleted it", "were removed per ADR-0015 once issue #90 landed", "this file previously recorded list_issues as having neither a type nor a milestones parameter". skill-author/references/retrofit.md (197 lines) is a one-time migration guide; it is loaded from improve.md and listed in sources.md, so remove those in the same change. These belong in git history or the ADR, not in context. Effort S.

Done (2026-09-12): see commit edcc57c on docs/simplification-audit. Historical narration stripped from kyberforge (ADR-0020) and git (ADR-0023) skill content; retrofit.md deleted along with its load-step and sources.md entries. Caught in review: some ADR-0023 tags were not narration but the check-rtk-prefix hook's required opt-out marker for intentionally-bare git commands — those 12 were restored, not left stripped.

  1. State repeated boilerplate once or delete it. A near-identical "Resolve owner and repo" block in 5 of 7 gitea skills; 404-masks-403 in 6 files; manual pagination in 7; main/master refusal in 9 git files; the "use the project's domain glossary, respect ADRs" paragraph in 5 bin skills. Three git skills define three different structured-result JSON shapes whose only consumer is git-orchestrate (finding 19). Effort S.

    Done (2026-09-12): see commit b4c3d5e. Trimmed each repeated instance in place — same meaning, fewer words — rather than extracting to a shared file (blocked by the one-file-per-skill install constraint, ADR-0014): the "Resolve owner and repo" block across 5 gitea-* skills, the 404-masks-403 note across 6 gitea files, the manual-pagination explanation across 8 gitea files, the main/master force-push refusal across 7 git plugin files (some with multiple internal restatements), and the domain-glossary/ADR paragraph across 5 bin skills. This was a trim-in-place pass, not a merge: the cross-skill duplication itself remains and is coupled to the (out-of-scope) skill-merge findings 19/20. Left the three git skills' structured-result JSON shapes untouched, as directed. Verified no regressions with scripts/skill-size-check.sh (pre/post diff) and claude plugin validate on both plugins.

4.2 kyberforge (290 files, 44,568 lines incl. mirror; the 7 SKILL.md bodies are 333 lines, under 1%)

  1. Merge skill-audit + agent-audit into one audit skill (removes about 3,300 lines and two pre-push hooks). vale-wrap.sh is byte-identical in both; five Vale rules byte-identical (agent-audit carries one extra, so it is the superset); validate.sh shares a 1,061-line boundary-target resolver block that diffs as zero lines; SKILL.md steps 1, 3, 4 and the gotchas are the same text. Each copy is hard-wired to one mode, so the merged script needs a path switch. The duplication exists because a plugin-cache install copies only each skill's own files (the rule ADR-0014 follows), so a script cannot be shared across skills; merging the skills is the only way to remove the copy. Effort M.

  2. Merge skill-author + agent-author likewise. contract.md shares most of its Description section; new-skill.sh and new-agent.sh implement the same package-root walk-up with different mode names; step 1 dispatch tables and step 3 gates are near-identical. Keep the agent scope logic (plugin vs project/user) as its own reference. Effort M.

  3. Cut the validators by an order of magnitude. validate.sh is 1,677 lines of bash with embedded Python, ported twice; skill-size-check.sh is 1,497. Target about 200 lines total: frontmatter present, size ceilings, boundary targets resolve. The 526-line vale-wrap.sh exists to work around folded > scalars in descriptions; writing descriptions as | literal blocks removes the folding problem, but the wrapper is also the exported hook entry in .pre-commit-hooks.yaml and carries the NOT RUN guard the audits depend on, so it shrinks rather than disappears. This is where the real complexity lives and is the item most worth discussing. Effort L.

  4. Fold forge and apm-install. forge is a four-row routing table plus 207 lines of references explaining fork vs inline; it should be 25 lines with no references. apm-install (53 lines + 17-line sources) becomes a sixth dispatch row in apm-workflow. Effort S.

  5. Delete prose the model already knows. "Valid characters: lowercase letters, numbers, hyphens"; what pipx does and PEP 668; "code blocks carry a language tag"; "data to stdout, diagnostics to stderr". Ironically body-discipline.md instructs auditors not to include "concepts the agent already knows". Effort S.

4.3 git and gitea (153 + 93 files, 9,889 + 6,047 lines incl. mirror; source 3,288 + 2,286)

  1. Delete the two router skills and two orchestrate agents (309 lines + 195 reference lines). No skill invokes them as a step; they appear only in boundary clauses (AGENTS.md, git-worktrees, gitea-issues, gitea-prs) and as worked examples in agent-audit references, all of which must change in the same commit or skill-size-check fails on the dangling target. Claude Code already routes on descriptions. The chain today is git-workflow step 5 invokes git-orchestrate, whose step 5 invokes git-commits, which runs rtk git commit: three hops. Both agents exceed 900 words; ADR-0020 deliberately sets no agent body gate. Effort S.

  2. Collapse git 7 skills to 1; gitea 7 to 2. Git references are man-page restatement: git-log-format.md (242 lines listing %H, %ar), conventional-commits-spec.md (170 lines), worktrees.md (178), merging.md explaining fast-forward. Roughly 60% of the plugin is generic. The genuinely house-specific content fits in about 150 lines: the rtk rule and ADR-0023 exceptions, main/master refusal, --no-verify, the -i --autosquash 2.39.5 trap, --force-with-lease --force-if-includes, bisect exit codes, submodule push ordering, the detached-HEAD worktree trap. Gitea is more legitimately specific (MCP schema quirks: tree_sha, withLines, silent drops on PR create, per_page 20 vs 30, 404 means 403) and splits naturally into gitea-tracker (issues, PRs, labels, milestones) and gitea-repo (branches, files, releases). Risk: one description must carry all trigger phrases; keep a dispatch table at the top of the body. Keep pc-author and pc-run (finding 38). Effort M.

  3. Delete config.example.json / .claude/plugins/git/config.json. Read by two steps, written by nothing. Default to GitHub Flow with the existing develop / release/* inference. Effort S.

    Done (2026-09-12): see commit 4bbd8a5. Deleted plugins/git/config.example.json (the runtime .claude/plugins/git/config.json was never a tracked file). Removed the config-read step from git-orchestrate's Process and from git-branches' Step 1, leaving the existing default-inference logic (GitHub Flow, with Gitflow inferred from a develop/release/* branch) as the sole path; updated git-workflow's description of the orchestrator's behaviour to match. Dropped the now-dangling applied_config field from git-orchestrate's output shape and the config.example.json example from docs/spec/architecture.md.

4.4 bin, core, lint (88 + 49 + 31 files incl. mirror)

  1. bin: strip generic process theatre. write-docs is 109 lines, mostly form-filling sections plus a 15-line source provenance block; its rules fit in 25 lines. tdd is about 70% textbook (RED/GREEN diagram, "good tests are integration-style", five thin references restating textbook design advice). diagnose 40%, prototype 50% (pixel-level UI switcher spec), grill-with-docs 35%. Keep the opinionated parts: "no horizontal slicing", "no phase 2 without a loop", [DEBUG-xxxx] tags, "never infer the output path", the triage state machine. Effort M.

  2. bin: merge grill-me into grill-with-docs. grill-me is 16 lines and a subset of the docs flow; grill-with-docs creates CONTEXT.md when missing, so the merged skill needs a no-write opt-out. caveman (50 lines) and zoom-out (9) are hand-invoked prompts rather than workflow skills; they are also the repo's disable-model-invocation exemplars in CONTEXT.md, contract.md, ADR-0020, ADR-0021, and gates.md, and install.sh has no path for ~/.claude/commands/, so moving them means picking a new exemplar. improve-codebase-architecture defines its glossary twice (inline and in language.md; the README documents the split as intentional). Effort S.

  3. core: provider-adapter-author is a 1,200-line wrapper around one instruction ("replace duplicated lines with @AGENTS.md, keep provider-specific lines"): a 496-line validator with a 519-line bats suite for a check that is a grep. agentsmd-author already calls agentsmd-audit as mandatory closeout, and both route to provider-adapter-author in boundary clauses that must change with it. Target: one agentsmd skill with an audit mode, adapter conversion as a step, validator about 40 lines. Needs an ADR-0012 revisit. Effort L.

  4. lint: delete the lint-runner agent. Its body is "call vale-run, reformat output", which --output=JSON already gives; it exists for backends that do not exist. It is the example boundary clause in three agent-author templates and ADR-0016, so those need a new example. About 40% of vale-config is install tables and settings lists the model can fetch from vale.sh. Keep the house-verified matrices (E100/E201, Packages below glob, frontmatter, ignore paths). lint/docs/research/docs/vale/ overlaps the skill's own references by about two thirds. Effort S.

5. Prose and docs (9,600 lines, 109,000 words outside plugins)

  1. Move or delete docs/research/ and docs/notes/ (4,500 lines, 47% of prose words). Six of eleven research files are linked only from each other; they are self-described session audit trails, agendas, and a "temporary build reference". docs/notes/factory-research-gaps-conflicts.md says "Status: Superseded"; factory-integration-decisions.md says "Complete" and its decisions already live in ADRs, yet AGENTS.md tells every session to read it. archive/team-self-organisation-sprint-brief.md (3,400 words) is unrelated to this repo. Archive or delete; drop the three AGENTS.md pointers. Moving CONTROLS.md to docs/spec/ means updating its literal path in nine or more files including the deployed governance.md. Effort S.

    Decision (2026-09-12): Keep. Same reasoning as finding 9 — these docs are intentional context for sourced work. Not proceeding.

  2. Four governance documents say one thing. core/instructions/governance.md (949 words, always-on), docs/ai-constitution.md (2,906), docs/wiki/HUMANS.md (1,413), CONTROLS.md (1,224), with near-identical preambles and, in three of the four, a "what this file does not govern" block pointing at the others. The constitution repeats one of its own principle lead sentences. Keep governance.md as the operative file, trimmed to about 50 lines (drop the classification table that repeats the bullets above it, the footer, the non-governance block). Dedupe the constitution by about 20%. Effort M.

  3. ADRs: 2,740 lines, 72% in eight ADRs over 150 lines. ADR-0020 is 513 lines with a 71-line measurement log as Context; ADR-0017 has 173 lines of amendments against 45 of decision. ADR-0001 is superseded and ADR-0006 moot, both keeping full text below the banner. ADR-0002 is three lines. Truncate superseded ones to the banner, fold amendments into the decision, cap Context at 20 lines, add a 25-line docs/adr/README.md index with status. The rules already live in gates.md; the ADRs need only decision and consequences. Effort M.

  4. The same facts are stated in full three or four times. "Edit .apm/, never the mirror": README (2 paragraphs), AGENTS.md (2 paragraphs), architecture.md (2 paragraphs plus the lost-README anecdote), ADR-0017. The apm.lock / SessionStart story: README (11 lines), AGENTS.md, ADR-0018, ADR-0019, gates.md. The offline SKIP= command and the three-stage install each appear three times. Rule: README has the how-to, AGENTS.md has one-line rules with links, architecture.md has mechanics. Effort S.

  5. LESSONS.md: 41 entries, 2 graduated, about 12 stale. Twelve entries from 2026-05-17 describe a write-skill / write-eval workflow whose skills no longer exist. One entry is open work labelled "Status: neither part landed". The longest eight are 200 to 550-word incident reports. Delete the stale entries, move open work to an issue, cap entries at about 60 words, target 100 lines. Effort S.

    Done (2026-09-12): see commit 629320b on docs/simplification-audit. 255→131 lines, 41→30 entries. Kept 3 of the same-dated entries (RLHF defaults, secrets-rule gap, HITL gap) — judged unrelated to the defunct write-skill/write-eval workflow and still applicable, so 10 deleted rather than 12. The "neither part landed" open-work entry (CONTEXT.md not @imported at session start) was removed rather than filed as an issue — full text preserved in this session's transcript if wanted later.

  6. CONTEXT.md: 28 terms, most used only by gates.md, scripts, or tests rather than by skills; two (Preload tax, Skill context contract) are never used outside CONTEXT.md and ADR-0020. The preload-tax entry quotes two dated numbers then says not to quote them. The example dialogue and flagged-ambiguities sections are grill residue. Cut to about 20 one-line terms. Effort S.

  7. Structure is described three ways (README layout table, architecture.md plugin table, AGENTS.md structure bullets), and VISION.md carries a 35-line stack spec for a product that lives in another repo. One layout table in README; architecture.md keeps mechanics only; VISION drops the stack detail. Effort S.

6. Distribution, versioning, and session startup

Not covered by the area audits above; found on a final sweep of the root config and install pipeline. The install pipeline itself (scripts/install.sh 55 lines, deploy-manifest.sh 24, statusline 109) is fine and needs nothing.

  1. Every plugin version lives in four places (five for kyberforge), plus one per skill. plugins/<name>/apm.yml, two generated plugin.json files, the root apm.yml packages list, the executables.allow key (kyberforge#1.6.2), and a metadata.version in all 39 SKILL.md files (ADR-0022) that nothing consumes and that drifts freely (gitea skills sit at five different values). Repo tags (v2.0.1) follow a third scheme that the declared tagPattern: v{version} can never match under per_package versioning. ADR-0006, ADR-0022, check-executables-allow-sync, skill-frontmatter, and apm pack --check-versions all exist to police this. Proposal: one version per plugin in its apm.yml; drop metadata.version and ADR-0022; let apm pack derive the rest. Effort M.

  2. The SessionStart hook auto-updates the install on every startup. check-apm-current.sh runs apm outdated (network, 60 s timeout) and then apm update --yes (300 s timeout) at every session start, rewriting apm.lock.yaml. That is why the lock file is dirty at the start of this session and why AGENTS.md has to explain "commit or discard it deliberately". It is a 60-line script with a 368-line test, an ADR (0019), the executables.allow pin, and a sync hook behind it. For a repo that is its own source, the update belongs in install.sh or a manual apm update, not in session startup. Effort S to remove; the design question is whether auto-update at startup is wanted at all.

  3. Outputs and packages for consumers that do not exist. The codex output profile generates .agents/plugins/marketplace.json (95 lines) although Codex is not a supported consumer. The mattpocock-skills remote package entry is the only reason apm-marketplace-check needs the network, and its pin is advanced by hand (ADR-0015). The .github/plugin/marketplace.json mirror is a legacy path (finding 2). Removing all three leaves one generated marketplace manifest (the per-plugin plugin.json pairs remain) and no network-dependent hook. Effort S.

  4. The release-tag mechanism guards an external contract with no known consumer. .pre-commit-hooks.yaml exports three hooks for other repos to pin by rev: <tag>. check-release-needed (242 lines + 442 test), test-vale-hooks-consumer (270 lines), ADR-0014, and three tags exist to serve that. If no other repo pins these hooks today, the whole mechanism can be deferred until one does. Effort S.

  5. Two .mcp.json files declare an Obsidian vault server over docs/ (root and plugins/bin/; the other five plugin .mcp.json files are empty stubs), while AGENTS.md forbids using an external memory system for this repo. If the Obsidian tools are unused, drop both and the reinject_mcp_servers explanation in the bin README; the bin plugin.json pair regenerates. Effort S.

  6. pc-author / pc-run (689 lines) carry generic pre-commit documentation. hooks-by-language.md (128 lines) and failure-patterns.md (133) restate pre-commit.com. Keep the skills, trim to the house-specific rules. Effort S.

7. Suggested order

  1. Quick wins, all S, no design decisions needed: findings 9, 10, 26, 30, 31, 29, 12, 13, 1, 6, 4, 35, 37, 38, and the mirror-sync and executables-allow halves of 2. Removes roughly 25,000 to 30,000 lines and 6 hooks.
  2. Structural changes that need a short discussion: 14, 15, 19, 20, 23, 25, 17, 3, 5, 7, 33, 34, 36.
  3. The real complexity: 16 (validators), 11 (provenance), 24 (core), 8 and 28 (gates.md and ADRs).

Findings 9, 10, 11, and 12 are coupled through the provenance validator and the audit criteria; land them together or the audit gates start reporting the removals.

8. Questions to settle before starting

  • Native Claude Code marketplace install vs apm-only. The flat mirror, check-plugin-content-sync, and ADR-0017 exist only for native claude plugin install. If apm install is the only supported path, the mirror and its 2,100 lines of tooling go away. Which install paths must work for consumers?
  • Copilot CLI legacy path. Is .github/plugin/marketplace.json still read by any Copilot version you target? If not, finding 2c is a pure delete.
  • Provenance chain. Is "which upstream informed this file" a requirement you still want, or was it a governance experiment? Finding 11 hinges on this.
  • ADR-0012 (three core skills) and the one-script-per-skill install constraint. The merges in 14, 15, and 24 need the first revisited and are the only way around the second. Are you open to superseding ADR-0012?
  • Granularity of git/gitea skills. One git skill vs seven trades routing precision for size. Is one broad description acceptable?
  • Auto-update at session start. Do you want the install refreshed from the remote every time a session opens (finding 34), or is a manual apm update acceptable?
  • External hook consumers. Does any other repo pin this repo's .pre-commit-hooks.yaml by tag today? If not, finding 36 defers the release mechanism entirely.
  • Obsidian MCP. Are the Obsidian tools over docs/ used by anyone? If not, finding 37 is a pure delete.