Neither has a real consumer: Codex is not a supported target, and
mattpocock-skills was the sole remote marketplace.packages[] entry
forcing apm-marketplace-check and apm-pack-check-clean to git
ls-remote on every push. Removing both drops .agents/plugins/marketplace.json
(the codex output artifact) and makes every pre-push hook resolve
fully offline. Updates README, AGENTS.md, gates.md, architecture.md,
and ADR-0015/ADR-0021 to match.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
Cut the "Verified fixed" reproduction paragraph carrying explicitly
stale pre-retrofit figures, and condensed the "Current retrofit
status" section's issue-#99 process narrative to the current-state
facts and the commands to check them.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
skill-frontmatter was a 62-line bash script inlined in
.pre-commit-config.yaml, re-parsing SKILL.md frontmatter with grep and
awk to check for name/description/metadata.version fields.
skill-size-check.sh already parses the same frontmatter block with
PyYAML for its ADR-0020 checks, so the two checks belonged in one
script.
Adds a ~20-line required-frontmatter check (name, description,
metadata.version as three-part semver) to scripts/skill-size-check.sh.
Removes the inline skill-frontmatter hook from .pre-commit-config.yaml
and deletes tests/test-skill-frontmatter.sh (366 lines). Removes the
79-line "the other hook on that scope" discussion from
docs/spec/gates.md and its now-dangling cross-reference, replacing
both with a one-line note of the fold, and updates the pre-push hook
counts there.
Updates fixture builders in test-skill-size-check.sh,
test-adr0020-body-checks.sh, test-adr0020-targets.sh,
test-adr0020-differential.sh, and test-vale-hooks-consumer.sh to carry
valid metadata.version so the new check doesn't spuriously fail
existing fixtures that predate it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
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
Finding 21: `config.example.json` (and the never-tracked
`.claude/plugins/git/config.json` it documented) was read by
git-orchestrate and git-branches but written by nothing, and the
default-inference fallback (GitHub Flow, with Gitflow inferred from a
`develop`/`release/*` branch) already covered the no-config case.
Removed the config-read step from both, updated git-workflow's
description of the orchestrator to match, dropped the now-dangling
`applied_config` field from git-orchestrate's output shape, and
deleted the config file and its stale example reference in
docs/spec/architecture.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
The #113 sweep rested on CLAUDE.md's premise that rtk either filters or passes through unchanged,
so prefixing is always safe. Measured against rtk 0.42.4, that premise is false for several of the
commands the sweep prefixed, and two skills were left giving wrong answers silently.
Why:
- `rtk git worktree list --porcelain -z` discards both flags and renders its own format. The
`locked`/`lock_reason` fields git-worktrees Step 2 must emit are absent entirely, and paths under
$HOME are abbreviated to `~/`.
- `rtk git branch --list <name>` prints a phantom `* ` line even when nothing matches, so
git-branches' stated ambiguity test — "output from both means the name is ambiguous" — reported
every name as ambiguous. `tag --list` is a clean passthrough, so only one half broke.
- `rtk git diff --name-only`/`--name-status` append a `Changes:` trailer to output documented as
"one per line"; `--word-diff` emits none of the `[-removed-] {+added+}` markers its table
describes; `rtk git log -L` truncates each line at ~72 chars, on the one command whose purpose is
showing line content.
- `rtk git stash pop` prints only `FAILED: git stash pop`, swallowing the conflict diagnostic and
retained-entry message the surrounding prose tells the agent to rely on.
Implementation notes:
- Eleven sites reverted to bare `git`, each carrying its reason inline so the next sweep does not
undo it. `mergetool` and `rebase -i` are reverted on clause 3's interactive limb only: the TTY
defect does not reproduce — rtk filters exactly twelve subcommands and execs the rest — and
ADR-0023 records that measurement rather than a convenient one.
- ADR-0023 states the rule repo-wide with a third clause: a command whose output the skill parses,
or which is interactive, stays bare. `plugins/git/README.md` is reduced to a pointer; its claim
that gitea skills "contain no git/rtk mentions at all" was false, and its citation of
`hard-rules.md` pointed at a file containing no occurrence of "rtk".
- Eight gitea sites swept, all verified byte-identical passthroughs first.
- `scripts/check-rtk-prefix.sh` gates clause 1. Run against main's pre-sweep corpus it reports 99
findings including every gitea site, so it would have caught the drift #113 was filed about.
Impact: the gate covers clause 1 only, in shell-tagged fences and the opening span of Run cells.
Clause 2 is not gateable — "Run `git switch`" and "`git switch` refuses" are the same tokens — and
prose bullets are invisible to it. Both limits are recorded in gates.md rather than left implied.
Refs: #113
ADR: 0023
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
The hook is `entry: bash` with `args: ['-c', <script>]`. pre-commit appends filenames after the
script string, so the first becomes `$0` and never enters `"$@"` — on a single-file commit, the
common case, the loop body never ran and the hook reported Passed having measured nothing.
ADR-0022 leans on this hook as the enforcement for a mandatory `metadata.version`, so the vacuous
green was the whole gate.
Implementation notes:
- An arg0 placeholder absorbs `$0` so every filename lands in `"$@"`.
- Checks now run against the YAML frontmatter block only, extracted with awk. The old
`grep -A10 "^metadata:"` matched a `metadata:` inside a body code fence, spanned past the block
into a following `source:` entry's `version:`, accepted any indentation, and missed a `version:`
more than ten lines in. An unreadable frontmatter block is now an error, never a pass.
- The value is asserted against three-part semver. `write-docs` carried "1.0" through the entire
ADR-0022 retrofit undetected, which a presence-only check cannot catch.
Impact: `tests/test-skill-frontmatter.sh` is the first test this hook has ever had. It drives the
real `entry`/`args` composition read out of the config rather than a copy of the script, which is
the only shape that catches the arg0 bug; against the pre-fix hook it scores 7/20.
gates.md described the hook wrongly in both directions and is rewritten, with a carve-out
explaining why this one stays a shell parser next to the "python3 and PyYAML are hard
requirements" reasoning that argues otherwise.
Refs: #127
ADR: 0022
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
Retrofits all 39 skills to ADR-0020's description/body context contract, then fixes what six rounds of independent review found in that retrofit — including four ways the hot gate itself failed open.
Closes#99, #107, #108, #110, #111, #114, #115, #120.
## The retrofit (waves 1-5)
| | Start | Now |
|---|---|---|
| Description FAILs (>400 chars) | 26 | **0** |
| Body FAILs (>900 words, body-only) | 9 | **0** |
| Dangling routing targets | 2 | **0** |
| `Kyberforge.CompositionNote` | 10 | **0** |
| Preload tax | 21,005 chars | **~10,500** |
Under the 12,000-char success criterion. Per-wave detail is on #99.
## The review fixes
**The gate failed open four ways, three of them found after the retrofit shipped.** An unrecognised follower token made a dangling target vanish. A skill directory with no `SKILL.md` resolved as a valid target, so a commit could be green locally and red in a fresh clone — three existing fixtures were relying on that, one of which made the install-leak A/B pass vacuously. Then the free-standing `/name` sweep turned out to be gated on the sentence carrying a boundary marker, so route notation in any other sentence was invisible — not an ERROR, not a SUGGESTION, not an INFO — which left the documented "`/name` always blocks" promise false from a second direction. All four fixed and pinned.
**Two checks were silently not running.** `validate-provenance.sh` checks 7-8 were dead across nine skills. Waking them exposed a deeper problem: they assume `Research doc:` names a source index, but 30 of 121 entries point at topic content documents, so every new check-7 INFO was a false positive and check 8 was saved from a false-FAIL flood only by an *unannounced* skip. Checks 7/8 are now scoped to source indexes and every skip announces itself (#121).
**The retrofit's own anti-goal, four times.** ADR-0020 warns that a blunt gate gets satisfied by deleting content rather than relocating it. `diagnose` and `skill-audit` relocated prose and then read it unconditionally; `prototype` and `vale-config` deleted rules outright that survived nowhere. All four addressed.
## Verification
- `bash tests/run-tests.sh --strict` — 24 suites, 0 skipped, 0 failed
- `bash tests/run-bats.sh` — 325 tests, 0 failures
- `pre-commit run --all-files` — 17/17
- `pre-commit run --hook-stage pre-push --all-files` — 16/16, with `apm marketplace check` and `apm pack --check-clean` run against the remote, not skipped
- `scripts/skill-size-check.sh` over all 39 skills — rc 0, 0 ERROR/FAIL, SUGGESTION-only
- Preload tax measured at **10,498 chars**, max description 390 — both inside budget
- Every new test proven non-vacuous by a deliberate mutation of the behaviour it covers
**Per-commit sync, stated accurately:** the ten commits from the latest review round each pass `check-plugin-content-sync` in isolation, verified by checking each out in a detached worktree with a clean between. The earlier gitea window (`dfacf05..bedbd1d`, nine commits) does **not** — its mirror was regenerated in one batch at `bbc7300`. An earlier revision of this description claimed the property held for every commit; it does not, and a bisect through that window lands on a red commit. **Squash-merge** to collapse it, or accept that this range is not bisectable.
## Version bump
Six plugins and the catalog take a **patch**, not a minor. The branch is **89 commits — 40 `fix` / 30 `refactor` / 12 `docs` / 5 `chore` / 2 `test` — zero `feat`, zero `!`, zero `BREAKING CHANGE`** — and adds no skill, agent, command or hook. (Two earlier revisions of this section cited a stale histogram, most recently 78 commits; the figures above are measured at HEAD.) Both rules this repo ships (`forge/references/version-bump.md`, landing in this PR, and `git-commits/references/conventional-commits-spec.md`) make that a patch, and the catalog set is unchanged at 7 entries.
Not settled by that: four published files were removed from the installed tree, three moved, and `caveman` gained `disable-model-invocation`, retiring its old triggers. Under a strict reading those are major-class and currently ship under `refactor:` with no marker. Whether the deployed skill surface is a public contract is written down nowhere — worth deciding, but it outlives this PR.
## Deliberately not in scope
#112 (cherry-pick ownership, now resolved in favour of `git-commits`), #113 (`rtk git` normalisation), #116 (research fan-out), #101 (audit-skill merge), #122 (non-spec skill-root files), #123 (no PRD producer) stay open. #117 is the one worth reading: the contract's remedy is to move prose into `references/`, which is exactly where neither the size gate nor Vale looks — and the blind spot is wider than #117 currently records, since there is no root `.vale.ini` at all, so every ADR, `CONTEXT.md` and `README.md` is unlinted too.
That blind spot let this branch carry two `level: error` `Kyberforge.SentenceOpenerThereIs` violations into `references/` files it created — `provider-adapter-author/references/provider-matrix.md:31` and `agent-audit/references/finding-criteria.md:95`. Both are reworded in `afadaae`, confirmed by routing each file through the audit's own `vale-wrap.sh` (1 error each before, 0 after). Five further occurrences sit in `references/` files already on `main`; those are the pre-existing corpus and stay with #117, which is the real fix.
Also unfixed and not this PR's: `apm install` appends a duplicate `SessionStart` entry to `.claude/settings.json`, so a fresh clone cannot get pre-push green without an edit AGENTS.md warns against. Reproduces identically on `main`.
Co-authored-by: Defame1297 <gitea@rkdr.net>
Reviewed-on: https://git.dev.rkdr.net/Defame1297/holocron/pulls/129
Co-authored-by: Claude Code AI - Gitea MCP <claude@noreply.git.dev.rkdr.net>
Co-committed-by: Claude Code AI - Gitea MCP <claude@noreply.git.dev.rkdr.net>
Why: two blind verifiers re-ran the five preceding commits and found four
defects of the same class this branch exists to close -- a confidently stated
measured claim that does not survive re-measurement -- this time inside the
fixes themselves.
- AGENTS.md:41 still carried both phrasings c68e864 reports having corrected.
`grep -rn repo-defined` returned exactly one hit repo-wide: that line, in the
file every session preloads. 4d336bb edited the line directly above it.
- ADR-0021 asserted twice, in the section justifying that no gate is added,
that the ADR-0020 validators "never open an apm.yml". All three open and
yaml.safe_load it (skill-size-check.sh:342, both validate.sh). The conclusion
survives -- none reads the description: key, and their globs are SKILL.md and
*.agent.md only -- but the stated mechanism is falsified by one grep.
- architecture.md said the ADR directory holds 20 numbered ADRs; c7ba3d2 made
it 21, and c68e864 audited that file for exactly this class of stale count.
The number is dropped rather than corrected: `ls docs/adr/` is already the
index, so a count in prose is a second thing to maintain.
- gates.md's new three-verdict table said `-> name` promotes an unresolved
target to ERROR. Reproduced with fixtures: NAME_HYPH (skill-size-check.sh:543)
requires a hyphen, so `-> gitea-prs` is checked and `-> triage` is not
extracted at all, and the unicode arrow is never recognised. The SUGGESTION
text advises that spelling, so taking its advice can silence the finding. The
gap is now documented as a defect; nothing covers it, since the one arrow case
in test-adr0020-targets.sh happens to use a hyphenated target.
Implementation notes:
- AGENTS.md:48's coverage claim is shrunk rather than chased. Restoring six
glossary entries did not make it true: 12 more sampled terms are undefined,
three of them (trigger/capability/boundary clause) used inside CONTEXT.md
itself. It now says CONTEXT.md is the glossary and is not exhaustive.
- CONTEXT.md's output profile and near-miss entries are corrected against their
sources. The first stated a false exclusion -- .github/plugin/plugin.json IS
apm-generated; only the marketplace mirror has no profile. The second
inverted its source's referent: description-quality.md defines a near-miss as
a query, not a sibling skill.
- The strict-mode message named jq, which no suite guards on (`command -v jq`
appears nowhere in tests/), while omitting python3/PyYAML, which three do.
- README's git and gitea bullets now name git-workflow and gitea-workflow.
ADR-0021 leaves README the only inventory and architecture.md now points at
it, so the two bullets that were short had to be completed.
- ADR-0018's 2026-08-14 correction is marked superseded in place. It asserted
machine state in the present tense that its own 2026-08-17 note retracts.
- ADR-0021's remaining errors: six files -> four (measured from de84d1b), the
wiki description's length 114 -> 96 chars, the codex self-contradiction, the
cost argument overstating bumps already owed for any skill addition, and two
claims about files this branch went on to edit.
- The "15 of 17 suites" figure is restored where I had removed it: it is a dated
record of one incident, not a live count, and four sites now describe it the
same way.
Impact: 16/16 pre-push hooks pass, suite 24 passed 0 skipped 0 failed. No
behaviour change; every edit is prose or a comment.
Refs: #105
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmFqzpuExLJv3m114XVE9w
Why: the relocation into gates.md and architecture.md moved text faster than it
verified it, and a review found eight assertions that do not survive contact
with the repo.
- gates.md cited docs/research/examples/, which does not exist; the tree is at
plugins/kyberforge/docs/research/examples/. The same wrong string survives at
ADR-0013:98, where it originated, and is tracked separately.
- gates.md's description-budget arithmetic was built on 23,427, a figure
ADR-0020 measured at f9b919d and pins there, and compared a name-inclusive
total against a description-only ceiling. Dropped rather than re-measured,
following the precedent this branch set for CONTEXT.md's token figure: a
second live copy is a second thing to go stale.
- gates.md listed "every boundary-clause routing target must resolve" as a hard
FAIL. skill-size-check.sh emits unresolved targets as SUGGESTION by default,
promotes to ERROR only when terminal and either route-notated or corroborated
by a resolving target in the same sentence, and reports INFO DID NOT RUN when
no universe resolves. Verified with five fixtures; replaced with a
three-verdict table.
- gates.md and README called `pre-commit run --hook-stage pre-push --all-files`
the whole push gate. check-release-needed.sh exits 0 unless
PRE_COMMIT_REMOTE_BRANCH is refs/heads/main, which only the real git hook
exports -- its own header comment titles this a "Known gap".
- "repo-defined" was loose: the two meta hooks are also declared here, and what
separates them is repo: meta from repo: local.
- architecture.md claimed `when:` appears in two of 39 skill sources. Exactly
one SKILL.md carries it; the second hit is a META.md. The likely origin is
skill-implementation-workflow.md:233, which claims META.md sits alongside
every skill when one exists in the whole tree.
- architecture.md said core/AGENTS.md is "deployed beside" CLAUDE.md.
deploy-manifest.sh sends them to ~/.claude/ and ~/.agents/ respectively; the
relation is import, not adjacency.
- gates.md's see-also cited ADRs as bare stems where its neighbours use paths.
Implementation notes: architecture.md's closing pointer sent readers to the
published description "for what a consumer actually gets", which was true
against an enumeration and is not after ADR-0021. It now names the boundary
relationship and points at the skills tree and README for an inventory. README's
bin bullet gains caveman and zoom-out, since ADR-0021 leaves it the only place
an inventory lives.
Impact: 16/16 pre-push hooks pass. Deliberately not fixed here and tracked
separately: the 12 pre-commit-stage hooks gates.md does not document, its own
SentenceOpenerThereIs violation, and README's missing scripts/install.sh step.
Refs: #105
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmFqzpuExLJv3m114XVE9w
Why: the review found architecture.md's plugin table and README's plugin list
were both written by enumerating what happened to be in each plugin, so both
went stale immediately — README credited `git` with pull requests it has no
skill for, and both omitted `pc-author`/`pc-run`. bb9158d fixed this same class
on `core` in August and it recurred here, so the fix is to stop enumerating in
the place whose job is routing.
Implementation notes:
- architecture.md's table now states routing boundaries only, with a note saying
so and pointing at each plugin's published apm.yml description for the actual
inventory. Two boundaries are named explicitly: `core` vs `kyberforge` (kept),
and `git` vs `gitea` — wire protocol against a local clone versus the forge's
HTTP API, which is why git-branches and gitea-branches are not duplicates.
- The `git` row is widened to cover git hook tooling rather than moving
pc-author/pc-run elsewhere. pre-commit manages .git/hooks/, so the placement
was always right and the row was simply under-described.
- README's setup block had a comment where step 2's command should be. It now
carries `pre-commit install -t pre-commit -t commit-msg -t pre-push`, verified
against the three stages in .pre-commit-config.yaml and the three hooks in
.git/hooks/. pc-run is still named, as the option rather than the only path.
- README:11 said each plugin carries agents, hooks and MCP servers. Only
kyberforge ships hooks and only bin ships an MCP server.
- gates.md:30 claimed its hook list was in config order; it is grouped by
concern, which is the better layout, so the claim is corrected to match.
Impact: docs-only. gitea's published description is corrected separately, since
that regenerates consumer-facing manifests.
Why: 1929ffd and b9c7762 preserved every constant, hook ID and error string,
but two don't-re-litigate notes were lost. Both were guard-rails — they fired
from preloaded context, before the mistake. Restoring the sentence to an
on-demand spec doc restores the text without restoring the function, since an
on-demand file is opened after a plan is formed, not before.
Implementation notes: placed by when each note must fire, not by what it is
about.
- "Do not expect `apm pack` to refresh the .github/plugin/marketplace.json
mirror" now lives in the DRIFT failure message of the script and hook that
already catch that exact mistake. It costs no preloaded tokens, fires at the
moment of the error, and cannot be missed. No test asserts on that message;
--check and shellcheck both pass.
- Plugin self-containment has no gate that fires on it, so it goes in
architecture.md's Plugin model beside "self-contained plugin units", stated as
the constraint it is rather than a description, with the two consequences that
make it load-bearing: the duplicated Vale styles (ADR-0014) and ADR-0020's
constants copied into three validators.
Impact: the every-session set is unchanged — neither note returns to AGENTS.md.
Why: CONTEXT.md is an instructed every-session read at 33,799 bytes (~8,450
tokens), and CONTEXT.md:17 layered docs/VISION.md on top. After the AGENTS.md
trim, that left ~9,650 tokens of instructed reads sitting behind a file whose
own format contract — grill-with-docs/CONTEXT-FORMAT.md:43, "Keep definitions
tight. One sentence max." — it was not following. 22 glossary entries averaged
190 words; the top four were 55% of the file, and one ("Vale audit prefilter")
was 1,444 words of pre-commit forensics filed as a definition.
Implementation notes:
- CONTEXT.md rewritten to CONTEXT-FORMAT.md's prescribed template: ## Language
(five clusters, 22 terms with _Avoid_ aliases), ## Relationships,
## Example dialogue, ## Flagged ambiguities. 33,799 -> 9,762 bytes.
- Vale prefilter forensics moved to docs/spec/gates.md under nine subsections:
the two-copy style layout, vale-wrap.sh and the Vale 3.15.2
text.frontmatter.description limitation, the --config argv defect (E100),
glob scoping, the rule inventory, and 0-files-means-NOT-RUN.
- Instruction-file format and the bidirectional-reference principle moved to
docs/spec/architecture.md, the latter flagged as aspirational: no instruction
file carries a `when:` field, only 2 of 39 skills do, and the reference
scanner script it names does not exist.
- Added a per-plugin scope table to architecture.md so "which plugin owns this
skill" survives the trim, and corrected its claim that the content index
lives in providers/claude-code/CLAUDE.md — that file is now two import lines
and the index sits in core/AGENTS.md.
- "Repo and Gitea are the only source of truth" moved from CONTEXT.md's
Principles into AGENTS.md session rules; it was operative guidance in a
glossary. docs/VISION.md and LESSONS.md added to the on-demand list.
- The apm-consumed install entry (432 words) was deleted outright: all four
consequences are already carried by README.md, ADR-0018, gates.md and
AGENTS.md.
- ADR-0013, ADR-0015 and ADR-0017 each pointed at CONTEXT.md sections that
moved; amended with dated supersession notes rather than left dangling.
Impact: the every-session set drops from ~15,700 to ~4,140 tokens across both
passes (-74%). The deleted "lint plugin" entry was also stale on a safety
claim — it said lint-runner inherits Edit, but ADR-0016 restored
`disallowedTools: Edit, Write, NotebookEdit` and CONTEXT.md was never updated.
Refs: #99
Why: AGENTS.md is preloaded into every session via CLAUDE.md's @AGENTS.md
import, so every word is a tax paid whether or not it is relevant. It had
grown to 3,371 words (~4,550 tokens), 75% of it a single "Setup and testing"
section that was mostly neither: roughly 1,600 words were gate forensics —
why a hook is shaped the way it is, what was tried and rejected, verification
numbers — and only ~390 words were genuine one-time setup.
Implementation notes: split three ways by audience rather than by heading.
One-time setup, prerequisites and test commands move to a new root README.md,
which did not previously exist. The gate forensics move to a new
docs/spec/gates.md, preserving every constant, hook ID, error string and
tried-and-rejected note (policy.fetch_failure_default, the removed fallback
frontmatter reader, extending skill-size-check's files: pattern to agents,
tidying .claude/settings.json out of the pretty-format-json exclude list) —
these exist to stop settled decisions being re-litigated, so none were
dropped. AGENTS.md keeps only what applies every session, at one clause of
rationale per rule. The .apm/-mirror section collapses to a pointer because
docs/spec/architecture.md already covers it in full. The hot ADR-0020 gate
counts stay in AGENTS.md deliberately: they block any skill edit today.
Also corrects docs/spec/architecture.md's stale claim of 19 ADRs; ADR-0020
landed without updating the count.
Impact: per-session preload drops from ~4,550 to ~1,116 tokens, a 75% cut.
agentsmd-audit passes: secrets clean, drift clean, 4 informational findings
for sections deliberately relocated to the README.
Why
---
ADR-0018 left deployed skills tracking the remote default branch with nothing
watching for drift. The mechanism that was supposed to cover this,
scripts/git-hooks/post-push, could never have worked: git has no client-side
post-push hook. install.sh copied it into .git/hooks/ so it looked installed,
and it had never once fired. Issue #78 reported it as skipping the gitea
plugin; it was skipping everything.
Refreshing on push was also the wrong shape. Your install goes stale when
someone else merges, so a push of your own is neither necessary nor sufficient
for staleness to have occurred.
Implementation notes
--------------------
kyberforge ships a SessionStart hook (startup matcher only) that runs
`apm outdated`, and when anything is behind runs `apm update --yes` and returns
reloadSkills:true so the running session picks up redeployed content. It exits
silently with no apm.lock.yaml present, which keeps it inert for hosts that
installed this plugin natively rather than through apm.
Two findings drove the wiring, both verified rather than assumed:
- apm resolves ${CLAUDE_PLUGIN_ROOT} against the installed package root, and
`apm pack` keeps only *.json from .apm/hooks/. A .../hooks/<script> reference
therefore points into the generated mirror where the script does not exist —
apm reports "Hook script not found" and deploys a hook aimed at nothing. The
reference must be .apm/-relative, and a test pins it.
- apm's executable-trust gate is OFF unless apm.yml carries an `executables:`
block; until now every hook, bin and MCP primitive a dependency shipped would
have deployed unprompted. Root apm.yml now enables it. The allow key is
version-pinned by apm's design, so a kyberforge version bump silently blocks
the hook until the key is bumped too — called out in the block and the ADR.
Also corrects ADR-0018 and AGENTS.md, which named `apm install` as the refresh
command. It is not: `apm install` deploys from apm.lock.yaml's pinned commit
and does not re-resolve refs. `apm update` does.
Impact
------
Session startup costs ~0.7s when current and ~10.4s when six packages are
behind. Auto-refresh rewrites apm.lock.yaml, so an unexplained modification to
it after opening a session is expected; the emitted notice says so.
.claude/settings.json stops being exactly {"hooks": {}} once the hook lands
there — the merged entry is apm's own output, and the rule that nothing
repo-authored goes in that file is unchanged. .claude/hooks/ and the
.claude/apm-hooks.json sidecar are gitignored install output.
The hook cannot install itself: dependencies resolve from the remote, so it
takes effect only after this merges and `apm update` runs once against the new
default branch.
scripts/git-hooks/ is now empty. install.sh's copy block is kept and
test-git-hooks-install.sh synthesizes its own fixture, so the mechanism stays
tested without requiring a dead hook to exist.
ADR: 0019
Refs: #78
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X7GvKuJfy2WrdBmUttV4DT
Why:
The repo published apm packages but consumed them the old way — `claude plugin install
<name>@holocron`, six plugins enabled per project. Dogfooding stopped one layer short of the
install tooling kyberforge itself ships.
Implementation notes:
- Root apm.yml declares the six packages as dependencies.apm git+path objects against the
holocron remote. Object form over `<name>@holocron` aliases on purpose: an alias first needs
`apm marketplace add`, which writes to ~/.apm/marketplaces.json — user scope, absent on a fresh
clone. Unpinned against the default branch, matching the autoUpdate the native install had.
- apm.lock.yaml is committed; .claude/skills/, .claude/agents/ and apm_modules/ are gitignored
regenerable install output. Committing the deployed skills would add a third mirror of content
ADR-0017 already governs two copies of.
- .mcp.json is generated by apm from plugins/bin/.mcp.json, so the obsidian MCP server survives
the switch.
- .claude/settings.json is reduced to {"hooks": {}}. apm replays the install into a scratch tree
and diffs, so any repo-owned key there is permanent drift that fails apm-audit-ci. Nothing was
lost: enabledPlugins was empty after the uninstall and the only hooks entry was PreToolUse: [].
- tests/run-bats.sh and tests/run-tests.sh exclude apm_modules/. It holds a full copy of every
plugin, and a copied .bats file resolves its helpers against the dependency root rather than
this repo — 334 tests, 167 failures before the exclusion.
Impact:
Skills are now unnamespaced — `git-commits`, not `git:git-commits` — because apm deploys plain
project skills with no plugin to prefix. AGENTS.md, CONTEXT.md and docs/spec/architecture.md are
updated accordingly. Root apm.yml now declares dependencies, which arms apm-audit-ci's
lockfile-exists check for the root manifest. External consumers are unaffected: the marketplace
manifests are untouched and `apm pack --check-clean` stays clean. Project scope only.
ADR: 0018
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X7GvKuJfy2WrdBmUttV4DT
AGENTS.md told an offline agent to push with SKIP=apm-marketplace-check and
asserted that hook was "the only one whose failure mode is 'no network'".
Running all 12 pre-push hooks under a network namespace shows two fail, for
one shared cause: apm-pack-check-clean resolves the same remote entry. An
exact pin does not remove the ls-remote, so both hooks are named now.
AGENTS.md also said everything in a plugin root except .apm/ is generated.
Plugin roots carry hand-authored README.md, docs/, bin/, sources.md and
.mcp.json, so an agent would hunt for an .apm/ source that does not exist or
refuse the edit. The rule is positional: immunity belongs to the plugin root,
and anything inside a mirrored directory is still rm -rf'd.
ADR-0017 said apm strips a hooks field. The real loop is (agents, skills,
commands, instructions) -- hooks absent, instructions never mentioned -- and
it can never fire, because synthesize_plugin_json_from_apm_yml only emits the
eight identity fields. The decision stands; the mechanism was overstated. Its
mcpServers amendment is rewritten for the pointer payload and now records the
real reason: inlining bypassed apm's credential sanitizer.
ADR-0015's owner.email and version-pin passages are corrected against the apm
source, and ADR-0016 gains the disallowedTools amendment. agent-audit's
allowlist is data, so it gains disallowedTools too -- the ADR and the
validator that enforces it had come apart.
architecture.md described a root CLAUDE.md that imports two files (it imports
one, plus an RTK block) and pointed at an ADR index that does not exist.
Seven skill READMEs listed tests/ files the mirror strips, promising installed
users files their install lacks; those rows are marked source-only, with the
depth-4 template tests explicitly called out as surviving. And
plugins/kyberforge/hooks/README.md, deleted during the conversion and
preserved nowhere, is restored to a path the mirror does not own -- verified
by running a sync against a scratch copy.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X7GvKuJfy2WrdBmUttV4DT
Documentation asserted things the code no longer did, which is how several of this
round's defects survived three review passes.
- `docs/spec/architecture.md` still described the pre-APM model — "each plugin has a
`plugin.json` manifest" — when no such file exists. AGENTS.md routes agents here
for the current structure, so it was live drift, not archive. Also cited ADR-0012
where ADR-0003 is meant.
- AGENTS.md never said `.apm/` is the sole hand-edited source, while the generated
mirror is byte-identical with no marker — an agent reading only AGENTS.md would
edit the mirror and find out at pre-push. It also omitted that `apm` and `jq` are
now required to push, unlike the `vale` bullet that exists for exactly that reason,
and understated the pre-push gate. `apm marketplace check` hard-fails offline and
`--offline` does not help, so the `SKIP=` escape hatch is documented rather than
new machinery built.
- ADR-0017 carried hardcoded line numbers that drifted twice within one PR, and said
`mcpServers` reinjection was real-syncs-only where the script's own header says
both modes. Line numbers dropped rather than corrected.
- ADR-0015 asserted issue #90 was closed. It is open. Reworded to defer to the
issue's own state rather than depend on someone remembering to close it.
- ADR-0014 said both audit skills pass `--config`; both SKILL.md files say pass none,
and passing one fails with E100. The ADR was wrong.
- ADR-0007 cross-referenced an archived ADR-0011 whose number was later reused.
Disambiguated with a note — renumbering a published ADR rewrites an immutable
record and breaks every existing citation.
- CONTEXT.md claimed `lint-runner` is report-only via a missing `Edit` tool.
Plugin-scope APM agents cannot express `tools:` (ADR-0016), so it is report-only by
instruction now; ADR-0016 accepted that regression but CONTEXT.md was not updated.
- Recorded two undocumented consequences of the conversion: `displayName` dropped
from all six compiled manifests and `owner.email` from the marketplace, and
`mattpocock-skills` silently version-pinned and manually maintained.
- Wrote the version-bump policy issue #90 specified but never delivered. Its previous
carrier, `marketplace-author`, was deleted in this PR, leaving the per-package rule
documented nowhere.
- README fixes: kyberforge listed skills belonging to the `git` plugin and a deleted
hooks path, `bin` advertised an agents directory it never had, and the docs index
listed files that do not exist.
Refs: #90
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X7GvKuJfy2WrdBmUttV4DT
## Why
overview.md described the chunk-based delivery model, which is superseded
by the marketplace/plugin pivot. architecture.md was equally stale: it
described .agents/skills/ as the canonical skills source (directory does not
exist), a provider-manifest.sh symlink mechanism (never built), and sync.sh /
init-project.sh as existing scripts (Chunk 6, not yet built).
## Implementation Notes
- overview.md deleted; all cross-references scrubbed from AGENTS.md, CONTEXT.md,
and three notes/research files
- architecture.md fully rewritten: content deployment model reflects actual
install.sh behaviour (DEPLOY_FILES / DEPLOY_EXECUTABLES / DEPLOY_DIRS);
plugin model section added listing all 5 plugins; directory structure section
removed (was describing a layout that no longer exists)
- "Chunk 6" phase label → "planned"; "chunk workflow" removed from AGENTS.md
description
- Fixed broken path docs/HUMANS.md → docs/wiki/HUMANS.md in governance layer
and core/instructions/governance.md
Refs: #15
## Why
ROADMAP.md was a static file that duplicated tracking information now
owned by Gitea milestones and issues. Keeping it created a maintenance
burden — references drifted out of sync with the actual state of work,
and agents were directed to read it when the source of truth had moved.
## Implementation Notes
All inbound references replaced with either the relevant Gitea milestone
("Skills & Agents") or removed where the context made them redundant.
Test assertions that verified ROADMAP.md content removed; test output
strings updated to drop the ROADMAP cross-reference instruction.
## Impact
Agents no longer read docs/ROADMAP.md at session start. Gitea milestones
and issues are the canonical source for roadmap and open-question tracking.
---
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Update docs to reflect pre-commit migration and cleanup:
- spec/overview.md: removed phantom test file references
- ROADMAP.md: removed references to non-existent test files
- LESSONS.md: removed reference to setup-hooks.sh bug
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
## Why
The convention requires living spec files to be updated in the same
commit as any behaviour change. Adding agent-author to kyberforge
without updating overview.md would leave the spec stale.
## Impact
kyberforge plugin entry now accurately reflects its three current skills
(skill-author, skill-audit, agent-author) and drops the outdated
reference to create-plugin, marketplace-architect, write-skill, and
write-eval which are no longer in the plugin.
---
Refs: #10
ADR: docs/adr/0015-agent-author-dual-provider-scaffold.md
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
No longer needed — kyberforge plugin-create provides a bundled template that
serves as the canonical scaffold reference. Remove hello-world from marketplace
manifests and update docs accordingly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Updates overview.md and architecture.md to document the kyberforge plugin,
the moved skills and evals, the removal of templates/, and the new plugins/
directory in the repo structure.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Complete 2026-05-18 workstream for write-skill refactor (issue 0018 phase 1).
Grill output (handoff in docs/issues/0018-factory-write-skill.md):
- 6-section standard replaces 8: Role and When/When not dropped (not in
agentskills.io spec; description carries trigger scope and negatives)
- Frontmatter reduced to 3 fields; provenance moves to META.md
(progressive disclosure — not loaded at every skill scan)
- SKILL-TEMPLATE.md and META-TEMPLATE.md as authoritative copy-fill artifacts
- CATEGORIES.md as self-contained category reference in skill directory
- Copy and fill explicitly split into separate process steps for determinism
New files in .agents/skills/write-skill/:
- SKILL-TEMPLATE.md — 6-section template with XML blocks and inline examples per section
- META-TEMPLATE.md — provenance schema with inline-commented YAML; source vs references explicit
- CATEGORIES.md — self-contained category table (no runtime dependency on factory docs)
- META.md — write-skill's own provenance (v1.1, self-authored)
SKILL.md rewritten: 8-step process, XML blocks (<requirements>, <steps>, <checks>),
3-field frontmatter, copy-then-fill steps explicit.
Supporting docs updated:
- skill-implementation-workflow.md: SKILL-TEMPLATE.md as authoritative template;
source:/references: now reference META.md; when: marked resolved
- factory-integration-decisions.md: frontmatter spec corrected
- ROADMAP.md: authoring standard description updated
- CONTEXT.md: Source field entry corrected; META.md added to glossary
- docs/spec/overview.md: 2026-05-18 refactor entry added
- docs/issues/0018: handoff status updated; acceptance criteria marked complete
LESSONS.md: 3 entries added in grill session (cargo-culted body sections,
provenance fields in frontmatter, copy-fill determinism) + 1 from implementation
(planning meta-commentary does not belong in deployed artifacts).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds write-eval, the first factory meta-skill. Produces eval.yaml test
files for skills following the two-section schema (trigger_tests +
output_tests) with provider-agnostic string assertions and show-plan-
then-merge-on-rerun behaviour. Hand-written bootstrap — subsequent
skills will use write-eval to produce their own evals.
Also tightens skill-implementation-workflow.md step 5b: per-section
options walk-through is now a named gate before writing, separate from
the synthesis grill. LESSONS.md entry added.
HITL behavioral test pending.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Create AGENTS.md at repo root and core/AGENTS.md as provider-agnostic
sources of always-on rules. Slim both CLAUDE.md files to thin adapters.
Deploy core/AGENTS.md → ~/.agents/AGENTS.md via deploy-manifest.sh.
Update three test suites to check correct locations post-refactor.
All automated tests pass (57 instructions, 106 install, 25 governance).
HITL behavioral test plan in test-instructions-and-docs.sh scenarios 9–12.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
14 issues created covering AGENTS.md refactor prerequisite, skill
implementation workflow grill, bootstrap skills (write-eval, write-skill),
remaining factory skills, and one issue per skill category group through
to chunk closure. All HITL; acceptance criteria for 0017-0028 to be
refined after 0016 grill session.
Doc updates: CONTEXT.md PRD/issue scope clarified (HOW distribution
across architecture-review and issue design notes); ROADMAP.md housekeeping
updated with bootstrap order and issue range; spec/overview.md recent
changes entry added; PRD updated (skills-index: delete → update).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Skills-index is now explicitly the canonical build reference for trigger
descriptions, constraints, and categories. Roadmap entry updated with
category breakdown, flat-path naming reconciliation (ADR-0009), authoring
standard reference, and delete-when-done instruction. Spec overview updated
to match.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
13 manual scenarios run across instructions and governance layers (two
rounds for failures). Fixed four rules that lost to RLHF defaults:
- Exploratory question format: tightened with boundary framing; added
@import CONTEXT.md to repo CLAUDE.md and a standing rule to check
docs/adr/ and ROADMAP resolved entries before answering design questions
(3-round iteration to resolve)
- File-edit intent: added counter-example to stop clarification-seeking
- Push confirmation: reframed as "do not call the tool" not "ask first"
- Secrets rule: extended to cover credential reproduction in response
text and usage examples, with explicit placeholder requirement
Scenario 4 (push confirmation) inconclusive — no remote configured.
Governance scenario 3 (HITL on real infra) untestable — Nginx not installed.
Both share the same root cause: agent delegates to permission system.
Also corrects stale skill list in docs/spec/overview.md (12 actual
deployed skills vs 16 names previously listed).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add LESSONS.md as the long-loop feedback log at repo root. Patterns
observed during development graduate to standing rules when three or
more entries appear.
Introduce docs/spec/ as the living spec layer: overview.md (deployed
state) and architecture.md (directory structure, install pipeline,
provider model, governance layer). Refactor docs/VISION.md to goals
and intent only — architecture content moved to docs/spec/architecture.md.
Update CLAUDE.md and CONTEXT.md to reference the new spec files.
Close issues 0013 and 0014. Update ROADMAP and factory integration
note to reflect completion.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>