Commit Graph

268 Commits

Author SHA1 Message Date
acaab29f89 fix(research): keep the allowed-tools list; it pre-approves tools, it does not restrict them
6683da5 dropped allowed-tools on the premise that the list blocked
spawning. The repo's own docs describe the field as pre-approval, so the
list was never the cause and dropping it widened the tool surface for
nothing. Restore the list and keep the parallel fan-out in steps 4-5.

The spawn tool is not added: its name is sourced for Claude Code
(Agent) but not for Copilot or Codex, so spawns prompt rather than
being pre-approved.

ADR-0027 still asserts the dropped-list premise and is corrected
separately.

Refs #116

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
2026-09-21 07:12:32 +00:00
6683da54ac fix(research): restore subagent fan-out, record that a skill body and its allowed-tools must agree
research instructed "spawn one subagent per URL" while its allowed-tools
granted no spawn tool, so it silently degraded to serial fetches. Three
other skills spawn subagents without trouble because they declare no
allowed-tools. The defect was the mismatch, not the spawning.

ADR-0027 records the agreement rule. research drops allowed-tools and
gets its steps 4-5 fan-out and the orchestrator-writes gotcha back
(1.0.1 -> 1.1.0).

Closes #116

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
2026-09-21 07:04:17 +00:00
0448f9cc01 feat(onedev): redistribute TOD's agent skills through a plugin wrapper
OneDev ships TOD, an official CLI, and eight SKILL.md files alongside it. apm installs raw
SKILL.md sources straight from a git repo, so those skills need no reauthoring — but a
`marketplace.packages` entry takes a local `source:` path, so a third-party repo cannot be
listed for redistribution on its own.

plugins/onedev is that wrapper. It carries no primitives yet: it pins
code.onedev.io/onedev/tod#v4.3.4 so consumers installing `onedev` from the holocron
marketplace pick up TOD's eight skills transitively, and it is where this repo's own OneDev
skills and orchestrator agent will live once there is a gap worth filling.

The pin is deliberate. The six first-party dependencies stay unpinned for default-branch
parity because they are this repo's own content; tracking a third-party project's main
would import an outside project's drift instead.

Impact: root apm.yml consumes the wrapper by git+path, so `apm install` does not resolve
until this is on the remote's main — including the copy kyberforge's SessionStart hook runs
on launch. Accepted deliberately; this merges immediately. Gitea remains the tracker of
record and ADR-0007 is untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwD8Egs5r4ndqeFLmhusX2
2026-09-20 19:39:08 +00:00
e849a823f7 fix(gates): report an unparsed routing clause beside a parsing sibling
boundary_clause_status() ran BOUNDARY_ARROW.search() and _arrow_targets()
over the whole description, so one arrow clause that parsed suppressed the
diagnostic for every other clause in it. A backticked hyphenated routing
target wrapped across lines in a folded scalar was therefore silently
unchecked -- no error, no suggestion, exit 0 -- whenever the description
carried one other clause that parsed. Written bare, the same wrap errors
correctly. That is the shape #100 regressed on.

The check is now per clause. Nothing that passed starts failing: all 68
routing targets across the 38 SKILL.md files resolved before and still do.
26 of those descriptions carry more than one arrow clause, so the
suppression was live across two thirds of the corpus, not an edge case.

validate-skill.bats pins the shape. test-adr0020-targets.sh's comment
described the #100 regression as a backticked wrap; the historical text was
unbackticked, which is precisely the shape the gate did not catch.

Also closes three README misroutes the branch left in the enforcement
layer: CompositionNote.yml's message, agent-description-quality.md:58 and
vale-wrap.sh's header still sent overflow to a skill-root README.md and
named the two skills ADR-0025 merged away. 1ec3e8a fixed the prose and
missed the rules that enforce it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwD8Egs5r4ndqeFLmhusX2
2026-09-20 18:37:45 +00:00
1ec3e8a1ea docs(skills): stop routing content at the README this branch deleted
skill-author still told authors to move description overflow "to the
body or to README.md" while this branch deleted every per-skill
README.md, every references/README.md and the README scaffold template.
factory-audit's skill-file-structure.md bans non-spec files at the
skill root, and the line that used to carve README out of that rule
went with them. So skill-author created the file, factory-audit failed
it, and nothing read it. 8ce5392 fixed the two scripts and missed the
reference prose.

The two contract.md files now differ deliberately: a skill's overflow
goes to the body or a references/ file, an agent's to the body alone,
because an agent is a single file with no references/ directory to
disclose to. agent-description-quality.md's "the plugin's README.md" is
left alone, plugin READMEs being the ones that survive.

Deleting retrofit.md also dropped three instructions baa2f5d did not
restore with the cut list, two of which retrofit.md itself recorded as
having no validator behind them: re-cite sources.md's Contributing
files after content moves, since validate-provenance exits 0 on exactly
that drift, and re-check a relocated gate's reachability, since a
Gotcha moved into one flow's file is invisible to the others and the
word counts improve either way. The third is that boundary clauses are
plural — contract.md read as a cap where git-remotes carries four.

Also: contract.md named an unqualified scripts/validate.sh that does
not exist in skill-author, which skill-file-structure.md calls a hard
error; and agent-body-and-delegation.md's simile pointed at a stale
README row as the characteristic skill defect, a defect class that can
no longer occur, replaced with a SKILL.md naming a references/ file
that is not there.

skill-author 1.0.4, agent-author 1.0.3, factory-audit 1.0.2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwD8Egs5r4ndqeFLmhusX2
2026-09-20 12:34:42 +00:00
82b7bbcf5c docs: close the PR #135 documentation review findings
Group 3 of the validated PR #135 review fixes. Every figure and commit
citation below was re-verified at HEAD before being written.

ADR and architecture:
- #7 ADR-0025 cited 61b0b9c, which no published branch reaches. Repointed
  to 620f20b (identical parent tree, reachable from the PR branch), with a
  note that neither is reachable from origin/main. The parser-drift
  paragraph now credits 598a7c3 (the reachable PR #129 squash) and keeps
  484357a only as a pre-squash parenthetical.
- #8 architecture.md dropped the pointer at the LESSONS.md entry this
  branch deleted.
- #9 architecture.md's ADR entry points now name ADR-0015 (the one
  compiler) and ADR-0024, and list ADR-0024 as superseding ADR-0017.
- #10 ADR-0024 section 4 rewritten: the standing patch-bump rule is
  apm-workflow's configure.md, not ADR-0006's, and this change does not
  trigger it. ADR-0015:93 carries a correction for the misattribution.
- N5 ADR-0021 gained a Correction note for the deleted
  scripts/check-manifests.sh (e647f14).

gates.md:
- #11a the four ADR-0020 constants live in lib-checks-skill.sh:313-316 and
  lib-checks-agent.sh:164-165, not in validate.sh.
- #11b the pretty-format-json exclude is two alternations expanding to
  three tracked files, including .claude/apm-hooks.json.
- #11c the ADR-0020 contract suite runs 28 -> 27 -> 29 (620f20b,
  4de5b6b, ef27c97), 29 at HEAD; the unverifiable 25 is dropped.
- #11d the boundary resolver is one copy since ef27c97.
- #12 apm-audit-ci documents the 10 root checks and the 1 plugin check
  apm 0.28.0 actually runs, that content-integrity IS the hidden-Unicode
  scan, that manifest-parse is not a named check, and that the hook needs
  a completed apm install. The offline claim is qualified accordingly.
- N9 gates.md:142-146 verified to still match the hook description.

AGENTS.md:
- #12 the no-network session rule is qualified to a populated
  apm_modules/.

Audit note:
- A1 hook counts corrected to 27/9 -> 26/8 -> 27/9 -> 26/8 (26 and 8 at
  HEAD) and the dangling pointer dropped.
- A2 skill-size-check.sh is 509 lines with the resolver sourced, not 1,522
  embedded; citations repointed to skill-size-check.sh:323-335 and
  lib-checks-skill.sh:235-283 (fail() at :265 and :280), and that library
  is 627 lines.
- A3 consumers receive 15 test files across 5 skills; 16 tracked test
  paths repo-wide.
- A4 the "do not run apm update on this branch" instruction is marked
  superseded, with the branch-aware guidance in its place.
- Finding 31's "true orphans" claim corrected for HOTL and Sycophancy,
  both still used in core/ai-constitution.md.

Same class, found during group 2:
- skill-author's deployment-modes.md no longer points at .mcp.json
  configs (deleted in c96ca9c); metadata.version 1.0.2 -> 1.0.3.
- git-orchestrate's context contract clarifies that
  user_config_overrides is caller-supplied session state, not a config
  read. The field name is unchanged.
- B3 root apm.yml's executables.allow comment: grants are version-blind
  in apm 0.28.0, so the #2.0.0 suffix is cosmetic to apm and a bump does
  not break the hook; the suffix stays because
  check-executables-allow-sync.sh requires it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwD8Egs5r4ndqeFLmhusX2
2026-09-19 21:30:29 +00:00
3920dfab20 fix(skills): drop references to deleted config and .mcp.json files
Closes four PR #135 review findings in skill content.

#2 — plugins/git/config.example.json was deleted in f5e4d0d, but four
git-plugin files still told the agent to read it. The file only ever
carried branching_pattern, commit_style and rebase_strategy, so the
`base_branch` and scope instructions were wrong even before the
deletion. Each site now describes what the skill actually does: base is
`main` under GitHub Flow or `develop` when Gitflow is inferred, the
Gitflow fallback keys off the repo's own branches, the orchestrator
contract's `base` defaults to the inferred base branch, and the commit
scope is inferred from the changed files.

N6 — gitea-prs was the one gitea skill with no permission-scope caveat
on a 404. Added one alongside the existing issue/PR number-space
guidance rather than replacing it: a 404 is only evidence of
"that number is an issue" once write:repository scope is confirmed.

N4 — plugins/kyberforge/bin/README.md pointed at `.mcp.json`, but all
six plugin-root .mcp.json files were deleted in c96ca9c (ADR-0018).
${CLAUDE_PLUGIN_ROOT} itself is still live, so the sentence now points
at .apm/hooks/hooks.json, which kyberforge's own hook already uses.

N7 — not applied. The finding claimed a marketplace field override
emits a verbose BuildDiagnostic that `apm pack -v` surfaces, so
"silently wins" was wrong. apm 0.28.0 does construct the diagnostic in
marketplace/output_mappers.py, but nothing renders it:
_render_marketplace_result in commands/pack.py iterates `warnings`
only, and BuildReport.diagnostics has no consumer. Confirmed on a
fixture — neither `apm pack -v` nor APM_LOG_LEVEL=DEBUG prints the
override, and --check-versions reports [matches]. The existing wording
in configure.md and marketplace.md is correct, so both are unchanged.

Version bumps required by check-skill-version-bump.sh: git-branches
1.0.4 -> 1.0.5, git-commits 0.1.6 -> 0.1.7, gitea-prs 0.1.4 -> 0.1.5.
bin/README.md is outside any skill directory and needs no bump.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwD8Egs5r4ndqeFLmhusX2
2026-09-19 21:17:14 +00:00
ea119d83b0 fix(gates): close six PR #135 review findings in gates and their tests
B1: check-skill-version-bump.sh resolves every merge-base with `git merge-base
--all` instead of the single base git happens to pick. A criss-cross history has
two, so the verdict turned on that choice: a skill byte-identical to main's tip
could still be reported "not above merge-base" / "not above main tip" and fail a
push that should pass. A skill now counts as changed only when it differs from
EVERY base, and its version must exceed the version at every base it exists at
as well as at the main tip; with more than one base the failure names which one.
Case 40 in tests/test-skill-version-bump.sh builds the criss-cross fixture and
pins both directions.

B2: check-apm-current.sh no longer assumes the remote default branch is `main`
when origin/HEAD is unset. A checkout whose default is `master` was standing on
its default branch and being told "this is a feature branch, so discard it" --
to throw away a real lock update. With origin/HEAD unset nothing is asserted and
the neutral advice stands. tests/test-apm-current-hook.sh covers the unset case
on both `main` and `master`.

#4: the required-frontmatter checks folded into skill-size-check.sh by c8a7c9e
were untested apart from the leading-zero shape -- mutating the missing-version
ERROR into a no-op left every suite green. tests/test-adr0020-frontmatter.sh now
pins name presence and non-emptiness, metadata.version presence and semver
shape, and the four grep defects the deleted test-skill-frontmatter.sh named.

#5: nothing asked whether a Vale rule still MATCHES anything -- rewriting
CompositionNote.yml's tokens to match nothing left test-vale-wrap.sh at 63/63.
Case 35 enumerates the rule files under the Kyberforge* style directories at run
time, requires an alert from each on its own fixture, and fails when a
discovered rule has no fixture row. The stale comment at case 31 is corrected.

#6: tests/run-tests.sh --strict exited 0 when discovery found no test-*.sh at
all; strictness only ever acted on skips, and with no suites there were none. It
now cross-checks the git index the way run-bats.sh does and fails
unconditionally on an empty set, naming the search root.

N9: the skill-size-check hook description in .pre-commit-config.yaml covered
only the size, context-budget and boundary-target gates. It now also names the
required frontmatter fields, matching docs/spec/gates.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwD8Egs5r4ndqeFLmhusX2
2026-09-19 21:08:10 +00:00
baa2f5dc7f docs(kyberforge): restore the retrofit cut order in skill-author
improve.md still required a retrofit before extending but lost the
procedure with retrofit.md. Restore the ordered cuts inline, and fix
the stale hook name and plugin-mode wording in skill-author's tests and
deployment-modes reference.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 15:27:32 +00:00
0323c2919b docs(git): restore the general bare-git rule in git-commits
The exception pointed at a Gotcha that does not exist. State the rule
(machine-parsed output or an interactive editor runs bare git, with the
reason inline) and point at rewrite-history.md for interactive rebase.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 15:27:30 +00:00
25743911f1 chore(release): bump the holocron catalog to 0.5.0 for the removed entry
Removing the mattpocock-skills entry is a minor catalog change under
apm-workflow's marketplace policy, not a patch. Also describe Copilot
support as reached through apm rather than a native Copilot CLI
marketplace (ADR-0024), and rebuild marketplace.json with apm pack.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 15:27:27 +00:00
8ce539238c fix(gates): stop pointing skill authors at README.md
Skills no longer carry a README.md, so the size advice in
skill-size-check and factory-audit's validator now names a references/
file instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 15:27:23 +00:00
ef27c9751a refactor(gates): source the boundary resolver into skill-size-check
Why: scripts/skill-size-check.sh embedded a byte-identical 1,061-line copy
of the ADR-0020 boundary resolver only because it was also exported
through .pre-commit-hooks.yaml, whose consumers could not reach a file
inside the plugin. 4de5b6b retired that export, so the hook now runs only
in this repo and can source factory-audit's lib-boundary-resolver.sh like
validate.sh does. One copy removes the edit-one-paste-the-other hazard.

Implementation Notes:
- The hook's Python program is assembled from its own preamble, the
  library's resolver and its own checks, read from quoted here-docs. The
  assembled program matches the old one line for line except one comment,
  and the hook's stdout, stderr and exit code are identical over every
  corpus SKILL.md and the 26 differential-suite fixtures.
- The hook fails closed, naming the library, when it is missing or
  defines no resolver.
- test-adr0020-contract.sh assertion 1 now pins the single copy: one
  marker pair in the library, none in the hook, fail-closed on a missing
  or gutted library, and a sentinel planted in a copied library that must
  appear in the hook's output. 1a expects exactly one authority. 27 -> 29
  passes.
- ADR-0020 and ADR-0025 carry dated amendments; gates.md and the
  library, hook and mode-library comments no longer describe two copies.
- factory-audit is new on this branch, so the version-bump gate exempts
  it; kyberforge is already at 2.0.0 against main's 1.6.2.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 13:25:16 +00:00
4de5b6b355 chore(gates): retire the external pre-commit hook contract
Why: .pre-commit-hooks.yaml and its release-tag gate served external
consumers that do not exist. No repo on the Gitea instance pins these
hooks, and the README names apm as the only supported install path. The
mechanism was also already failing: skill-size-check.sh changed after
v2.0.1 with no tag cut, and the gate cannot fire through Gitea's merge
button. (Simplification audit finding 36.)

Implementation Notes:
- Delete .pre-commit-hooks.yaml, scripts/check-release-needed.sh,
  tests/test-check-release-needed.sh and tests/test-vale-hooks-consumer.sh,
  and remove the check-release-needed pre-push hook. The repo: local
  skill-size-check and vale-audit-prefilter-* hooks are unchanged.
- ADR-0014 is amended, not retired: its runtime decision to bundle Vale
  inside factory-audit stands. The amendment keeps the entry[0]-only
  constraint (LESSONS.md:101,105) in case the export returns. ADR-0025
  gets a pointer.
- test-vale-wrap.sh: drop case 33 (the cross-manifest drift check) and
  case 28's hook-scope half, which read the published manifest. Case 32
  now also requires each hook to select every tracked file of its class,
  which keeps case 33's one-plugin-narrowing guard, with a mutation test.
- test-skill-size-check.sh and test-adr0020-contract.sh now assert the
  hook contract and verbose: true on .pre-commit-config.yaml only.
- gates.md: pre-push count goes from 9 to 8 authored hooks (11 to 10
  reported), and the Release table, the External consumers section and
  the two-manifest scope table are removed. README and script/test
  comments no longer describe the export as live. The resolver comment
  is edited identically in both copies.
- The v1.0.0/v2.0.0/v2.0.1 tags are left in place; they are inert.

ADR: 0014
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 11:52:14 +00:00
807caf22ee fix(kyberforge): give branch-aware advice for the refreshed apm lock
Why: the docs said to discard a refreshed apm.lock.yaml on a feature
branch because the refresh records main's commit, but the branch's own
lock records a (older) main commit too, and the SessionStart notice gave
the same "commit or discard" advice on every branch.

Implementation Notes:
- check-apm-current.sh picks fixed advice by branch: commit or discard
  deliberately on the default branch (origin/HEAD, else main), discard and
  reinstall on a feature branch; the branch name is never interpolated.
- README, AGENTS.md and ADR-0019 give the real reasons (no lock churn in
  the branch diff, deployed tree matches the committed lock), the cost
  (the session runs the older main) and that the next session start
  refreshes again.
- ADR-0019's check-clean and stale-server claims restated to match apm's
  source.

ADR: 0019
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 11:24:32 +00:00
398515bcad chore: drop the duplicated package descriptions from root apm.yml
Why: for a local-path marketplace entry, apm treats a root description: as
an override of the package's own apm.yml, reported only at verbose level,
so the "two copies stay identical" rule had no enforcement. Same fix as
2def060 made for version:.

Implementation Notes:
- All six root copies matched their package apm.yml before removal; the
  compiled marketplace.json descriptions are unchanged.
- apm-workflow references now scope the "omit it" advice to local-path
  entries: on a remote entry, version: is the semver range that selects
  the tag, and version: or ref: is required.

Impact: ADR-0021 amended; the package apm.yml is the single source.

ADR: 0021
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 11:24:22 +00:00
c5d43b4d63 chore(release): bump bin, git, gitea, core and lint patch versions
Why: each of these plugins changed shipped .apm/ content on this branch
without a package version bump, which configure.md requires and no gate
catches. No skill, agent or hook was removed, so a patch bump fits.

Implementation Notes: marketplace.json regenerated with apm pack; the diff
is the five version strings only.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 11:24:21 +00:00
1d40544075 fix(gates): hold skill versions above main's tip as well as the merge-base
Why: two branches that both bump a skill 1.0.0 -> 1.0.1 with different
content merge without a conflict, and each passed the gate against its own
merge-base, so main could ship two changes under one version.

Implementation Notes:
- check-skill-version-bump requires the pushed version to exceed both the
  merge-base and the main tip; failures name the baseline they missed.
- Presence is read from the tree, so a blob missing from a partial clone is
  a read failure instead of a silently exempt "new" skill.
- A leading UTF-8 BOM no longer reads as a missing version.
- Version parts reject leading zeros in all three validators
  (check-skill-version-bump, skill-size-check, factory-audit).
- New tests cover equal bumps, moved files, major/minor ordering, bad refs,
  unreadable blobs, mode-only changes, symlinks and tag peeling.

Impact: ADR-0022 amended (reverses "not main's current tip"); gates.md
updated to match, including pre-commit 4.6.1's exact ref selection.

ADR: 0022
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 11:24:08 +00:00
c07ca0767e docs(kyberforge): stop apm-workflow assuming root package versions
The root apm.yml packages[] entries no longer carry version:, and a
version there is a silent override that --check-versions does not
catch. configure.md and marketplace.md now name the package's own
apm.yml as the single source and drop version: from the examples.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 10:33:35 +00:00
8451169d2b feat(gates): enforce metadata.version bumps on changed skills at pre-push
check-skill-version-bump fails a push when a skill directory changed
against its merge-base with main (tests/ excluded) without a strictly
higher metadata.version than main. New, renamed and deleted skills are
exempt; every plugin is covered. Recorded as a dated section in
ADR-0022 and documented in gates.md.

Patch-bumps the 17 skills that changed on this branch without a bump,
so the branch passes its own gate. Simplification audit finding 33.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 10:09:56 +00:00
ffcbed6c41 fix(tests): replace pipefail-racy echo | grep -q with here-strings
Why

Two suites failed intermittently — tests/test-vale-wrap.sh case 21 and
tests/test-check-release-needed.sh cases 4 and 15 — on correct output, and never
when run alone. The cause is the `echo "$OUT" | grep -q P` idiom under
`set -o pipefail`: grep -q exits as soon as it has an answer, bash's echo can
hand a multi-line value to the pipe one line at a time, and a write after the
reader is gone kills echo with SIGPIPE. pipefail then reports the writer's
death, so output that DID match reads as "no match". Every observed failure had
lines after its match; case 15's match is on line 1 of 6, the widest window in
that file.

Forced with a pause before the writer's last line, the pipe form failed 50 of 50
runs; a here-string, a match on the last line, and the same pipe without
pipefail each passed 50 of 50. Unforced the rate is about 1 per 670 suite runs,
which is why it read as a flaky gate rather than a bug.

The failures at review time are consistent with this, but were not proven to be
it: the suite was running while agents edited live config files in place, and a
brief change to .vale.ini or .pre-commit-hooks.yaml would produce the same two
failures. The race is real and fixed either way.

Implementation Notes

`grep -q P <<< "$VAR"` has no separate writer process, so there is nothing to
race. It is not a retry or a sleep. 121 sites converted across 9 files, three of
them scripts rather than tests: new-agent.sh, new-skill.sh and
check-executables-allow-sync.sh. None ships via .pre-commit-hooks.yaml, so no
external consumer pins them, and all three are single-pipeline checks whose
verdict cannot change.

Left alone deliberately: 14 sites whose writer is a command, not a shell
builtin — they either absorb the writer's status with `|| true` or are python3
and awk, which write once at exit — and one file with no pipefail. `printf '%s'`
sites differ from a here-string only by a trailing newline, which no -q verdict
on a non-empty pattern depends on.

tests/test-no-pipefail-early-exit-grep.sh is a static guard against new
occurrences, discovered automatically by run-tests.sh. It only scans files that
set pipefail, joins continuation lines, skips comments, and flags only
echo/printf writers. Its first case proves the scanner can fail before its
second trusts a clean verdict on the tree.

A guard covers exactly the spellings its regex models, so the miss surface was
measured rather than assumed. Four were found and closed: pipefail declared as
`set -o errexit -o pipefail` (where the old pattern required pipefail to follow
the FIRST -o, and a file-level miss skips every site in that file); a writer
separated from grep by an intermediate stage; a pipeline wrapped on a trailing
`|` rather than a backslash; and readers spelled egrep, fgrep, /bin/grep,
`command grep` or with an env-var prefix. Segment characters exclude a bare `&`
so `echo ok && other | grep -q x`, whose writer is `other`, does not false-fire.
Widening surfaced 5 live sites invisible to the original scanner, all in
tests/test-apm-current-hook.sh, all `echo "$out" | json_field ... | grep -q`;
they are safe today only because json_field is python3, which reads to EOF and
writes once. Fixtures go 4 to 12 vulnerable spellings plus near-miss negatives.

Two `grep ... | head -1` sites (test-vale-wrap.sh) are the same race with a
different early-exiting reader, and are fixed by absorbing the writer. The
scanner deliberately does not model `head`, `sed -n 1p` or a bare `read`: most
legitimate uses in this tree are already absorbed with `|| true` and the scanner
cannot see absorption from pipeline text, so a high false-positive rate would be
how this guard gets weakened. Heredoc bodies are scanned as code; none in the
tree trips it today.

Impact

The bug predates the factory-audit merge: every converted site in
check-release-needed and case 21 dates to 4d018af and aa8cc22 (2026-08-09).

Test suites go 19 to 20. `run-tests.sh --strict` passes 20/20 with 0 skipped,
four consecutive runs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
2026-09-16 09:14:01 +00:00
620f20b0fd refactor(kyberforge)!: merge skill-audit and agent-audit into factory-audit
Why

The two audit skills carried 1,724 lines of byte-identical duplication: the ADR-0020 boundary
resolver (1,061), vale-wrap.sh (526), the Vale style rules (44) and the Contributing-files parser
(93). Nothing shared them — they were held in sync by a 413-line pre-push gate and its 797-line
test suite. Sync-by-gate had already failed once: at 484357a the two parser copies drifted into
different spellings of the bullet loop while a docstring asserted they were identical. That drift
was behaviour-neutral and was re-unified by hand at 598a7c3, so the copies were identical at merge
time — but nothing had caught it, and the next drift need not be neutral.

Implementation Notes

Self-containment binds BETWEEN skills, not within one. The agentskills.io spec forbids reaching
across skill directories, which is why two separate skills needed embedded copies; two files inside
ONE skill may source a third. That is the whole reason the merge removes duplication rather than
relocating it.

The union of both bodies measured 1,532 words against BODY_MAX_WORDS=900, and only 211 of those
words were shared, so SKILL.md is a dispatch body. Step 0 resolves the flow from the target path
before any validation, and its table mirrors validate.sh's detection exactly: a directory holding
SKILL.md or a SKILL.md file (skill); a *.agent.md, or a .md directly under an agents/ directory
(agent); anything else stops without running a validator. Steps 1-3 live in
references/skill-flow.md and references/agent-flow.md, and gotchas that apply to one flow live in
that flow's file, since it is loaded on every invocation anyway. If validate.sh reports on the
other artifact type, the body restarts at Step 0.

Named factory-audit rather than forge-audit because forge is a live skill, and a family prefix that
matches a live sibling reads as ownership rather than membership.

The description carries one arrow per boundary target, because ADR-0020 resolves only the first
target after an arrow. It drops the quoted "audit this skill"-style phrases, which restated
"audited" in a second register (ADR-0020's duplicate-register rule). 241 characters, Gotchas 16%
of the body: no size SUGGESTIONs.

The boundary resolver stays embedded in two files rather than imported: a cache-installed plugin
cannot read outside its own directory, and the repo-root hook resolves via .pre-commit-hooks.yaml
where entry[0] is the only token pre-commit rewrites, so no single file is reachable by both.
tests/test-adr0020-contract.sh hashes both copies for byte-identity, and asserts validate.sh sources
the resolver and that no third copy exists.

The entry scripts classify the target from its resolved parent directory, so a bare agent filename
typed inside agents/ works; resolve SCRIPT_DIR CDPATH-safely; and exit 2 when a lib-*.sh is
missing, rather than dying with exit 1, the tier the flows relay as real findings.

The provenance run functions stash their findings code in KYBERFORGE_PROV_RC and
return 0, so validate-provenance.sh calls them UNTESTED. Testing a function's
status (`f || RC=$?`) disables errexit for its entire body, and no subshell or
`set -e` inside can re-arm it once the call sits in a condition context
(measured, both spellings). Their error paths use `exit`, which is unaffected
either way; this keeps errexit armed for anything added later.

Case 0's readability guard reads the file instead of asking `[[ -r ]]`. `-r` is
access(2), which answers yes for uid 0 even on a mode-000 file, and this repo's
dev environment is root -- so the guard could never fire where it exists to fire.
A read attempt is also the stricter question, catching EIO. This is the reasoning
scripts/check-vale-style-sync.sh carried before this commit deleted it; the
hazard did not go with it.

All three entry scripts are CDPATH-safe, vale-wrap.sh included: both of its cd sites are cleared,
the --config resolution and the directory-mirror walk, where an exported CDPATH would otherwise
print a decoy path into the -print0 stream and build the mirror from the decoy's files. The two
remaining bare cd calls take absolute paths, which CDPATH is never consulted for.

Impact

BREAKING: skill-audit and agent-audit no longer exist as invocable skills. kyberforge goes to
2.0.0 (catalog 0.4.7).

Check logic is unchanged: differential runs of the old and new validators across every skill and
agent produced byte-identical stdout, stderr and exit codes, and the reconstructed Python payloads
differ only in comments and the references/field-inventory.md -> agent-field-inventory.md rename.
One doctrine governs the tiers: exit 0 is audited and clean, exit 1 is audited with findings OR a
target present but unreadable, exit 2 is that nothing was audited at all. Edge paths DID change,
deliberately (full table in ADR-0025):
- a missing target exits 2 (never ran), not 1, under its own "does not exist" message; detection is
  by path shape, so a shape-matching path that is simply absent used to reach the validator and come
  back as a FAIL against a file that never existed;
- an unshaped target exits 2 under the generic "matches neither" message, and a directory with no
  SKILL.md under a third, distinct one -- three exit-2 messages, not one;
- a dangling symlink or a symlink loop stays exit 1: it is present but broken, which is a finding
  about the artifact rather than a usage error;
- a SKILL.md file path is audited as its skill directory instead of refused;
- a .md agent outside an agents/ directory is refused rather than audited;
- a missing script library, a missing python3, a missing PyYAML, and no argument at all each exit 2.
  validate-provenance.sh already exited 2 for the last two; validate.sh now matches it.

.pre-commit-hooks.yaml is a published contract consumed by external repos. Both hook IDs and both
files: regexes are unchanged; only entry: and description: moved.

scripts/check-vale-style-sync.sh (413), scripts/sync-vale-styles.sh (21),
tests/test-check-vale-style-sync.sh (797) and agent-audit/scripts/README.md (47) are deleted. The
checker made 17 assertions: 6 compared the two Vale copies and are moot; 10 are rehomed into
tests/test-vale-wrap.sh (case 0, cases 28-31, and the suite's Vale-absent skip); and the
cross-manifest files: agreement check, which selected hooks by entry: and so could not survive both
hooks sharing one, is ported as case 33 pairing hooks by id:. Cases 28, 30 and 33 carry mutation
self-tests; narrowing the local skill prefilter to 6 of 38 SKILL.md files now fails the suite.

Skills go 39 to 38. Pre-push goes 9 repo-authored hooks to 8.

ADR: 0025
BREAKING-CHANGE: the skill-audit and agent-audit skills are removed. Both flows are served by
  factory-audit, which auto-detects whether it was handed a skill directory or an agent file.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
2026-09-16 09:13:57 +00:00
062ca47a18 docs: correct claims left stale by today's apm-only commits
A five-agent review of today's seven commits found no executable
regressions and no dangling references, but a set of documents still
asserting, in present tense, machinery that ADR-0024 and its commits
removed. This corrects them in place, keeping the original text as the
historical record wherever the repo's amendment convention applies.

LESSONS.md: the 2026-06-21 entry prescribed a `claude plugin validate`
sweep that now fails on every plugin, so it is marked superseded with
the surviving gates named. The 2026-08-09 entry gained a recurrence
note: today's manifest deletion broke apm's MCP propagation exactly as
that lesson describes, and its prescribed repo-local grep could not
have caught it, because `plugin_parser.py` ships in the apm toolchain
installed outside this repository.

ADR-0019, ADR-0011 and ADR-0021: amendments extended to passages the
earlier correction passes stepped over -- a dead native-consumer guard,
Consequences bullets still calling for a `plugins/gitea/.mcp.json` that
must not be recreated, and a drift-gate list naming a deleted script.
ADR-0021's list is down to one gate, not two: `apm audit --ci` never
read `description` and was never a drift gate.

architecture.md and enrichments.md: the self-containment constraint is
restated on its live source, the agentskills.io APM package-mode spec,
rather than on Claude Code's plugin cache-install, which ADR-0024
consequence 6 pins as a superseded rationale. releasing.md's pointer to
the deleted sync script is rewritten as history.

tests/run-bats.sh and scripts/lib/batch-run.sh: comment-only. The
`.claude/skills/` exclusion comment claimed a duplication that is not
live yet; apm does not strip `tests/`, and the deployed tree is empty
of them only because the lockfile still resolves the six dependencies
to a pre-ADR-0024 commit carrying the flat mirror. The exclusion is
correct but forward-looking, and now says so.

SIMPLIFICATION-AUDIT.md: reconciled against what the commits actually
did. Two closed findings recorded conclusions that ADR-0024 reversed
hours later; findings 1, 3, 31 and 35 carried prescriptions voided the
same day; finding 28 is now recorded as having moved backwards, with
docs/adr/ measured at +336 lines over the day. The section 1 headline
table is re-measured at a6434e0 and labelled with its basis. The
ADR-0012 contradiction between finding 2b and section 8 is resolved in
2b's favour after reading the ADR: only finding 24 is governed by it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
2026-09-14 19:50:23 +00:00
c96ca9ca0d fix: remove the obsidian MCP server and the unreadable .mcp.json files
718c79a deleted every per-plugin .claude-plugin/plugin.json, which
reclassified each package from a marketplace plugin to a plain apm
package. That silently broke MCP propagation: apm_cli/deps/plugin_parser.py
maps a plugin-root .mcp.json into .apm/.mcp.json, and that code path runs
only for marketplace plugins. With no manifest, apm never reads the file.

Reproduced on ref-pinned consumer clones: at the parent commit a consumer
receives the obsidian server, at HEAD it receives none, and on upgrade apm
prints "Removed stale MCP server 'obsidian' from .mcp.json". This repo
consumes its own plugins through apm (ADR-0018), so the tracked root
.mcp.json would have been rewritten to an empty server map on the next
lock re-resolve -- silent tool loss plus unexplained working-tree drift.

The server is removed entirely rather than relocated to .apm/. It was
already a standing question (SIMPLIFICATION-AUDIT finding 37, deferred on
2026-09-13 pending confirmation, now confirmed), and plugins/bin/apm.yml
declares dependencies.mcp: [] -- apm's supported mechanism was never used.
All seven .mcp.json files go; the root one is apm-generated output and is
now gitignored alongside the other install artifacts.

ADR-0011's deferred ".mcp.json wiring gap" is moot twice over -- the
install route it blocked no longer exists and neither does the file --
and ADR-0018 records why it lost its only worked example of MCP
propagation. apm.lock.yaml still carries the server; it clears on the
first apm update after this reaches the default branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
2026-09-14 18:09:17 +00:00
061bb3d5b4 docs: correct the apm-only change after a five-agent review
A five-agent review of 718c79a and d2480b8 found no skill, agent or hook
regressions (39 skills before and after) and confirmed both hook removals
are genuinely moot -- verified against the tree, not taken on the commit's
word. It did find one functional regression (fixed separately) and this
documentation drift.

Counting errors, all from a git pathspec `*` crossing `/`:
  - 17 .bats files shipped to consumers is really 10; 17 counted tracked
    paths merely containing /tests/, one of them a template asset
  - "roughly 88s off every push" is ~92.4s; 88 omitted validate-plugins
  - "roughly 70% of each plugin remains live" holds only for kyberforge;
    the real spread is 44.3% (bin) to 70.6%, now a table
  - the pre-push enforcement row was half-corrected: 33 entries stood
    unstruck (now 27) and 14 -> 11 switched counting basis mid-sentence
  - the root .claude-plugin/plugin.json was described as "kept"; it has
    never been tracked

gates.md said "Ten hooks" above a nine-row table (11 was decremented for
one removal, not two), and "both need the claude CLI" for one remaining
validator. Its pretty-format-json exclude rationale claimed six
alternations expanding to sixteen files in a passage headed "Mind which
number you are quoting" -- four alternations, two live files; the two
dead ones are dropped from the pattern. check-useless-excludes could not
catch this: it only flags an exclude matching nothing at all.

ADR-0024 cited ADR-0006 for a patch-bump rule it does not contain and
which ADR-0015 explicitly retired; stated apm's marketplace probe order
backwards (.claude-plugin/ is the last candidate, not the first, so the
earlier .github/plugin/ deletion only demoted resolution); undercounted
apm's skill-deploying targets as seven when there are fifteen; and never
recorded that validate-plugins was removed. The symlink hedge is resolved:
apm_cli/security/gate.py's ignore_non_content() drops symlinks silently on
deploy while apm_modules/ materialization dereferences them, so content
survives that far and vanishes at install. Accepted with no replacement
guard, per decision -- kyberforge/docs/hooks.md previously asserted a
guard that had been deleted with its script.

Four plugin READMEs still advertised `claude plugin install`; ADRs 0001,
0006, 0013, 0014, 0015 and 0019 described deleted machinery in the present
tense, 0019 most consequentially as the live justification for the
SessionStart hook's .apm/ path. CONTEXT.md's "apm package" entry forbade
"plugin" while using it in its own body, and "Output profile" lost the
antecedent for "one catalogue serves both".

run-tests.sh gains the .claude/skills/ exclusion run-bats.sh already had.
Latent today -- no test-*.sh lives under any .apm/skills/*/tests/ -- but
apm now deploys those directories, so one would be discovered twice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
2026-09-14 18:09:03 +00:00
718c79af70 chore: drop the flat content mirror and native install support (ADR-0024)
apm becomes the only supported install path. The flat mirror at each plugin
root existed solely so Claude Code's native `claude plugin install` could
convention-scan plugin content (ADR-0017). With no native consumers, it cost
~20,000 tracked lines plus ~2,100 lines of sync tooling and ~88s of every
push to guard content apm never reads — and its only automated gate,
`claude plugin validate --strict`, passes on a plugin with zero content, so
it could not detect the defect ADR-0017 was created to fix.

Removes the mirror (213 files), the six per-plugin manifest pairs,
sync-plugin-content.sh, its 1,289-line test, the orphaned
marketplace-plugins.sh, and the check-plugin-content-sync and
validate-plugins pre-push hooks. The root `marketplace:` block and
.claude-plugin/ catalogue stay: apm's own marketplace consumers read that
same file, so `<name>@holocron` short names keep working.

tests/run-bats.sh now excludes .claude/skills/. apm installs from .apm/,
which carries the tests/ dirs the mirror stripped, so deployed .bats files
would otherwise be discovered and double-run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
2026-09-14 16:59:42 +00:00
a622200868 docs(pc-skills): trim generic pre-commit boilerplate (finding 38)
Collapse the per-language hook tables in pc-author's hooks-by-language.md
into one shared-repo table plus an "other repos" table, dropping the
repeated repo/rev/rationale text that just restated what each hook does.
128 -> 92 lines. Kept both "Unverified — not in research corpus" flags
and the rev-freshness caveat.

Remove the generic SSH/proxy CI failure sections, the shellcheck SC-code
listing, and compress the generic validate-config schema-error bullets
in pc-run's failure-patterns.md, all of which just restated
pre-commit.com's own docs. 133 -> 109 lines. Kept the rtk-prefixed
re-stage/recommit fix (ADR-0023), the "do NOT reach for
`pre-commit install -f`" warning, and both gitleaks/shellcheck
not-sourced-from-corpus notes.

Combined cut: 60 lines. Flat mirrors regenerated via
scripts/sync-plugin-content.sh and verified byte-identical
(--check exits 0); no plugin.json drift.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
2026-09-13 20:54:17 +00:00
60d3005e67 docs(git): remove stale check-manifests/skill-frontmatter examples
f11b645 and bde9f7f swept check-manifests and skill-frontmatter
references left over from e647f14 and c8a7c9e, but missed two worked
examples in this vendored pre-commit research doc: a "Validate a
generated file" hook naming the deleted scripts/check-manifests.sh,
and a "SKILL.md frontmatter validation (inline bash, as used in this
repo)" example for the skill-frontmatter hook, folded into
skill-size-check.sh in c8a7c9e.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
2026-09-12 22:56:43 +00:00
bde9f7fdd8 chore: fix stale skill-frontmatter and check-manifests references
c8a7c9e folded the skill-frontmatter hook into skill-size-check but
left validate.sh's FAIL messages, skill-author's create.md, and the
skill template's frontmatter comment naming the deleted hook as the
enforcer -- misleading for anyone tracing a FAIL back to the gate that
raises it.

f11b645 swept check-manifests references but missed a hand-authored
"Local hooks in this repo" table in the git plugin's vendored
pre-commit research doc, which still listed both check-manifests and
skill-frontmatter as active hooks.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
2026-09-12 22:13:10 +00:00
6cfc3577e2 docs: trim repeated boilerplate in git, gitea, and bin skills
Finding 13: five blocks of near-identical wording were repeated across
skills within a plugin — the gitea "resolve owner and repo" step (5
skills), the 404-masks-403 note (6 files), the manual pagination
explanation (8 files), the git plugin's main/master force-push refusal
(7 files, some with multiple internal restatements), and the bin
skills' domain-glossary/ADR paragraph (5 skills). Tightened each
instance in place — same meaning, fewer words — rather than extracting
to a shared file, which ADR-0014's one-file-per-skill install
constraint rules out. Left the three git skills' structured-result
JSON shapes alone (coupled to the separate, out-of-scope git-orchestrate
merge candidate, finding 19).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
2026-09-12 19:48:31 +00:00
f5e4d0d082 docs(git): delete unused git plugin config file and its read steps
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
2026-09-12 19:46:28 +00:00
edcc57c0d6 docs: trim skill READMEs and ADR/changelog narration
Two related simplification-audit findings, bundled because they edit
some of the same skill-audit files and splitting would fragment
single-file diffs.

Finding 10: delete 48 per-skill/reference README.md files (they
restated SKILL.md in narrative form and no agent ever loads them) plus
2 scaffold templates. Drop the README criterion from skill-audit's
file-structure.md and finding-criteria.md, and the README-generation
step from skill-author's new-skill.sh; update new-skill.bats to match.
Plugin-root READMEs are kept intentionally, out of scope.

Finding 12: strip historical ADR-0020/ADR-0023 citations and
changelog-style narration from model-facing skill content across
kyberforge and git plugin skills. Delete skill-author's one-time
retrofit.md migration guide and its references. Some ADR-0023 tags
were not narration but check-rtk-prefix's required opt-out marker for
intentionally-bare git commands -- those were restored, not stripped.

Mirror re-synced and full pre-commit/pre-push suite verified green.

Refs: SIMPLIFICATION-AUDIT.md findings 10, 12

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
2026-09-12 18:38:09 +00:00
c75e4ef4f3 fix(bin): repoint improve-codebase-architecture README's LANGUAGE.md mention
PR #133 renamed the skill's root-level LANGUAGE.md to references/language.md
but missed a prose mention (not a markdown link) in the overview paragraph.
Fix both the .apm/ source and its generated flat mirror.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PDj6F7SPXzh3FtPN78dZ88
2026-09-10 19:12:16 +00:00
4f49b2a249 refactor(bin): move non-spec root files into references/ across four skills
grill-with-docs, improve-codebase-architecture, tdd, and triage kept
non-spec markdown files at their skill root, in violation of
skill-audit's file-structure.md rule (only SKILL.md/README.md belong
at the root; everything else lives in scripts/, references/, assets/
or tests/). A root-level file is invisible to the ADR-0020
dangling-reference gate, which only resolves unqualified
`references/...` pointers.

- Moved and renamed to lowercase-kebab-case under references/:
  grill-with-docs (ADR-FORMAT.md, CONTEXT-FORMAT.md),
  improve-codebase-architecture (DEEPENING.md, INTERFACE-DESIGN.md,
  LANGUAGE.md), tdd (five files, casing was already fine), triage
  (AGENT-BRIEF.md, OUT-OF-SCOPE.md).
- Updated every in-skill link to the new references/ paths, including
  link text that still showed the old uppercase filenames.
- Fixed improve-codebase-architecture/SKILL.md's cross-skill citation
  of grill-with-docs's two files to the sanctioned possessive form
  with the references/ segment included.
- Updated all four skills' README.md file tables to match.
- Regenerated the flat content mirror via
  scripts/sync-plugin-content.sh --all.

Fixes #122.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PDj6F7SPXzh3FtPN78dZ88
2026-09-09 19:59:02 +00:00
0f2bb242ad chore(plugins): sync generated content mirrors
Regenerates `plugins/*/skills`, `plugins/*/agents`, both per-plugin `plugin.json` manifests and the
two marketplace mirrors from `.apm/` per ADR-0017, via `scripts/sync-plugin-content.sh --all`.

The manifests matter beyond tidiness here: `plugin.json` carries the plugin version and wins over
the marketplace entry at install time (calculatePluginVersion precedence). Until this ran, the patch
bumps in the preceding commit were inert for anyone installing these plugins.

ADR: 0017
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
2026-09-09 05:15:53 +00:00
a3e721e937 docs: retire the META.md guidance ADR-0022 overruled, bump touched plugins
Why: ADR-0022 made `metadata.version` mandatory in SKILL.md frontmatter, but three documents still
instructed the opposite — that `version:`, `source:`, `references:` and `when:` belong in a separate
META.md. That recommendation was never implemented: META.md exists exactly once in this repo, inside
a vendored third-party research example, and all 39 skills now contradict it. A stale instruction
that outranks nothing is worse than no instruction, because an author following it undoes the ADR.

Implementation notes:
- Two LESSONS.md entries deleted outright — their entire payload was the rejected fix. Two kept and
  rewritten: the copy-fill entry loses only its META-TEMPLATE clause, and the `model:` entry keeps
  the provider-extension fact and the invocation-time boundary rule, which stand on their own.
- One factual error corrected in passing: the `extracted` slug entry claimed provenance is recorded
  in META.md. It lives in `references/sources.md` keyed by `source_keys:`, verified against
  validate-provenance.sh.
- Both docs/notes files gain `metadata.version` in their required-field lists. Deleting the stale
  paragraph while leaving those lists silent would have re-created the gap.
- `bin/write-docs` carried `metadata.version: "1.0"` — the only non-semver value in the corpus, and
  the result of relocating its old top-level `version:` without normalising it. Now `1.0.0`.
  ADR-0022 records the relocation it previously omitted, which issue #127 had asked it to decide.

Impact: patch bumps for the four plugins whose `.apm/` content changed — bin, git, gitea,
kyberforge. core and lint are untouched and stay put. Root apm.yml's `executables.allow` key and
marketplace package versions move in lockstep; the marketplace release version is unchanged.

Refs: #127
ADR: 0022
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
2026-09-09 05:15:41 +00:00
3811f5481b fix(kyberforge): unblock the scaffold and finish the #125 and ADR-0022 edits
Three related half-applied changes from #130, each leaving the corpus in a state its own
documentation contradicts.

Why:
- `assets/templates/SKILL.md` shipped `metadata:` fully commented out, and `new-skill.sh` only
  substitutes SKILL_NAME. Every scaffolded skill therefore lacked the `metadata.version` ADR-0022
  made mandatory and was blocked at first commit by the very hook this PR added. The commented
  example also read `"1.0"` — neither the `0.1.0` new-skill seed nor valid semver.
- `agent-audit/references/scope-project-user.md` still joined `disable-model-invocation` and
  `user-invocable` with a slash — #125's defect verbatim — while pointing the reader at the file
  this PR had just corrected to say the opposite.
- ADR-0022 required the "when present" bump conditional dropped and `metadata.version` moved into
  create.md's required list. It was dropped from SKILL.md but left in README.md, and the field was
  edited in place under a heading that still authorises removing it entirely.

Implementation notes:
- The template emits `metadata: version: "0.1.0"` live, captioned as required, with the optional
  keys left commented. `new-skill.bats` gains a case asserting a live key and three-part semver, so
  this cannot regress.
- `description-quality.md` now asserts only what the vendored Copilot research supports: two fields
  with opposite defaults, and the retired `infer` replaced by the pair rather than by either alone.
  The unsupported negative it previously stated as fact is gone.
- The `1.0.0` retrofit seed is stated in improve.md and retrofit.md, which the retrofit flow
  actually reads — create.md, where it lived, is unreachable from that path. The compression item
  moved out of the file-churn checklist, whose preamble excluded the wording-only change it covers.
- Executable git commands in these three skills now carry the ADR-0023 rtk prefix.

Refs: #125, #127
ADR: 0022, 0023
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
2026-09-09 05:15:23 +00:00
175ea89c0a fix(skill-audit): make check 9 reachable, wrap-safe and never silently skipped
Check 9 shipped in #130 to close #118, but three defects meant it could not do the job it was
added for.

Why:
- It is INFO-only, so it always exits 0 — and SKILL.md graded exit 0 "a genuine pass" and said the
  script "prints nothing on success". Every check-9 INFO was discarded before it reached a report,
  behind three further doors that only opened on a non-zero exit.
- `parse_field_raw()` matched `(.+)`, which does not span newlines, so only the first physical line
  of a wrapped value was compared. Rewriting only the continuation line of a wrapped Description
  from a hedge to a confident claim produced no finding at all — verbatim the regression #118 was
  filed about. The bullet branch had the same shape: a wrapped bullet broke the loop and dropped
  every later entry.
- A `git show` failure at the base ref was treated as "creation, nothing to flag" and skipped the
  whole skill with no output, collapsing "absent at that ref" with "not tracked under that name".
  A gitignored `.claude/skills/` copy reported clean while the authoring path reported four changed
  claims. The script's own usage text promises this is "never a silent skip".

Implementation notes:
- Exit-code guidance re-keyed on output as well as code: 0-and-silent passes, 0-with-output is
  INFO-only findings, 1 is FAILs, 2 never ran.
- `parse_field_raw()` is line-based and joins continuation lines; `normalize_field_text()`'s
  docstring is now true rather than aspirational. A reorder deliberately fires: the two fields share
  one parser, and order-insensitivity would mean splitting a prose Description on commas.
- The discarded `show_err` is now surfaced as one whole-check INFO naming both readings.
- `--base-ref=` given empty now beats the env var, as the usage text always claimed.

`validate.sh` gains an ADR-0022 `metadata.version` check at FAIL tier, because any lower tier lets
skill-author Step 4 report done on a file the commit gate then refuses. Its `read` heuristic now
skips here-doc bodies — reflowing the one offending line would have cleared the finding and left
the cause, since every usage() heredoc is one wrap from putting the English verb in column 0.

Impact: provenance tests 73 -> 82, validate tests 64 -> 72. Test 72 previously deleted origin/main
before asserting the override, so it proved the flag works with no default rather than that it beats
one; it now moves origin/main forward first.

Refs: #118
ADR: 0022
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
2026-09-09 05:15:05 +00:00
ed8c99efbd fix(git): stop prefixing rtk where it rewrites the output skills parse
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
2026-09-09 05:14:54 +00:00
af8b46cd57 chore(plugins): sync generated content mirrors
Regenerate plugins/*/skills/ from plugins/*/.apm/ after the previous
four commits, via scripts/sync-plugin-content.sh --all. The mirror is
generated output (ADR-0017) that check-plugin-content-sync's pre-push
hook diffs against .apm/; nothing here is hand-edited.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
2026-09-07 20:43:51 +00:00
09eea5e7ab fix(skill-audit): flag a changed provenance claim, not just its shape
validate-provenance.sh checked that a sources.md entry was internally
consistent -- slugs resolve, Contributing files exist, back-references
match -- but never whether the asserted contribution was true. A
retrofit once turned an honest hedge into a false confident claim and
every existing check passed it silently.

A literal-filename cross-check (flag a description naming a .md file
absent from Contributing files) was tried and rejected: 3/95 flagged
against the real corpus, all three false positives, and it would not
have caught the actual bug -- the bad description never named a
literal filename. No bash script can verify semantic truth, so the fix
uses what git can reliably detect -- a changed field -- purely as a
trigger for what can verify semantics: the auditor reading the files.

New check 9 flags (INFO only, never FAIL) any Description or
Contributing-files text change against a base ref (default: merge-base
with origin/main, overridable via --base-ref). A slug absent at the
base ref is a creation, not a change, and is not flagged. skill-audit's
rubric now tells the auditor a check-9 INFO means open the named files
and verify by reading, not just relay it. skill-author's retrofit
checklist gained a matching authoring-time guardrail: don't upgrade a
hedge into a confident claim without re-reading the source first.

8 new bats tests (73 total, 0 failures).

Fixes: #118
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
2026-09-07 20:37:03 +00:00
2c6ce438b6 refactor(git): normalize rtk-prefix usage, add metadata.version
Two bundled fixes across the same nine skills, since both touch the
same files.

Issue #113: skill prose used rtk git and bare git inconsistently for
the same operations, with no stated rule for which applied where.
Executable instructed commands (a dispatch-table "Run" cell, a fenced
code-block procedure, an imperative step) now consistently use rtk
git; illustrative or referential mentions -- naming a flag's behavior,
quoting a doc heading, warning against an anti-pattern -- stay bare
git. Documented in the new plugins/git/README.md, scoped to this
plugin only: gitea-* skills talk to the server over MCP tools and
carry no git/rtk mentions at all.

Also the git-plugin slice of #127: metadata.version added to the
eight skills that lacked it. git-commits already had one and is
untouched.

Fixes: #113
Fixes: #127
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
2026-09-07 20:36:49 +00:00
ffaa3afb41 fix(agent-audit): remove user-invocable as a hand-invoked marker
disable-model-invocation and user-invocable are independent Copilot
fields: the first gates whether the runtime auto-selects an agent (i.e.
whether its description is a routing string), the second only gates
manual invocation. An agent can be disable-model-invocation: false plus
user-invocable: false and still be model-routed, so the old bullet
conflated two unrelated contracts under one trigger.

Fixes: #125
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
2026-09-07 20:36:34 +00:00
60be7b3232 refactor(skills): mandate metadata.version on every skill's frontmatter
Only 12 of 39 skills carried metadata.version, and adoption tracked
which plugin a skill lived in rather than any stated rule: core,
gitea and lint were consistent adopters, bin and kyberforge were
consistent non-adopters, git was split with one outlier. There was
no documented convention, and skill-author's own bump logic was
already written as if presence were conditional.

metadata.version is now required on every skill. The 19 skills here
that never carried one (bin, kyberforge, gitea-files) are seeded at
1.0.0, not 0.1.0 -- that value stays reserved for a skill's actual
creation point under skill-author's existing convention. The
skill-frontmatter pre-commit hook now fails a SKILL.md missing the
field, the same class of failure as a missing name/description.

Full rationale in the new ADR. The git-plugin skills that also need
this field follow in the next commit, bundled with issue #113's rtk
normalization since both touch the same files.

Refs: #127
ADR: 0022
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
2026-09-07 20:36:24 +00:00
Claude Code AI - Gitea MCP
598a7c326a refactor(skills): retrofit the corpus to the ADR-0020 context contract (#129)
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>
2026-09-01 13:47:46 +00:00
967d3ade25 fix(gitea): document the remaining create/update parameter asymmetries
Follow-up to the review of #106, which found four parameter claims the
first pass left wrong or missing. All four verified against gitea-mcp
v1.6.0 source before changing anything.

`remove_deadline` is dropped on "create" like the others, but the new
Gotcha enumerated a closed list that omitted it — so the paragraph
contradicted its own opening sentence. The list is now open ("including")
and the parameter carries the same "update" only marker as its neighbours.

`base` is settable on "update": editPullRequestFn reads it and retargets
the PR onto a different base branch. The file documented it as required
for "create" and said nothing else, hiding a real capability. This one is
under-claiming rather than over-claiming, but a file whose subject is
which parameter applies to which method is the place to fix it.

applyDraftPrefix strips two prefixes, `WIP:` and `[WIP]`, matched with
strings.EqualFold, while only "WIP: " is ever added. The un-draft
correction said "the prefix" singular, which understates what a caller
can hand it.

README.md bundled `reviewers` and `milestone` into "creating and
updating". Capability prose rather than a parameter contract, so not
strictly false, but it is the same conflation that produced the original
bug and it is not behind any gate.

Not addressed here: SKILL.md's description still advertises updating
reviewers, its draft guidance still prescribes the manual workaround, and
its milestone-resolution instruction carries no method qualifier — so an
agent working from SKILL.md alone can still reach the failure mode. Those
edits trip skill-size-check and the Vale prefilter, pulling in the
ADR-0020 retrofit; tracked on #99 rather than done silently here.

Refs: #104
Refs: #99

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETxbGFetkbJQBHsx442Brt
2026-08-17 17:29:06 +00:00
4c9d2d7751 fix(gitea): correct which pull_request_write params apply on create
The gitea-prs reference documented `milestone` as "settable on both
"create" and "update"". It is not: `pull_request_write method: "create"`
accepts the parameter, returns no error or warning, and discards it.

Verified against the gitea-mcp v1.6.0 source rather than by observation
alone. `createPullRequestFn` builds its `CreatePullRequestOption` from
owner, repo, title, body, head, base, draft, labels and deadline only —
so the drop is not limited to `milestone` as issue #104 supposed.
`assignee`, `assignees`, `reviewers` and `team_reviewers` are discarded
on create too, and `reviewers`/`team_reviewers` are discarded on
"update" as well; they are only ever read by "add_reviewers" and
"remove_reviewers".

Two properties made the original error easy to make and hard to catch,
so both are now written down next to the correction: `labels` sits
beside `milestone`, reads identically, and does apply on create; and
`issue_write method: "create"` honours `assignees` and `milestone`, so
the asymmetry is specific to pull requests.

While in the file, corrected the adjacent draft gotcha. It prescribed
reconstructing the un-prefixed title by hand to un-draft a PR;
`applyDraftPrefix` shows "update" with `draft: false` and no `title`
fetches the stored title and strips the prefix server-side.

Impact: documentation only, no behaviour change. Callers following the
old text silently created PRs with no milestone, assignee or reviewer.
Confined to references/pull-requests.md, so the ADR-0020 skill gates do
not apply and gitea-prs needs no #99 retrofit first.

Fixes: #104
Refs: #99

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETxbGFetkbJQBHsx442Brt
2026-08-17 16:58:56 +00:00
c7ba3d2ccf chore(apm): retire skill enumeration from published descriptions
Why: enumerating a plugin's skills in its published description has now failed
three times in four days, the third time inside the correction for the second.

bb9158d (Aug 14) fixed core's description, which described bin's skills. That
failure was wrong content, not an incomplete list -- a syntactically perfect
four-item enumeration that belonged to a different plugin -- so enumerating
harder could not have caught it, and bb9158d's own fix replaced the enumeration
with a domain boundary. 65bac15 and de84d1b then cited that precedent while
doing the opposite, and the re-enumeration is itself incomplete: caveman and
zoom-out are unnamed in bin, git-workflow is unnamed in git despite 65bac15's
message claiming it was added, and gitea-workflow is unnamed in gitea. 23 of 27
skills named at the third attempt.

Nothing checks any of this. check-manifests.sh does not contain the string
"description"; apm audit --ci, apm pack --check-clean and
sync-plugin-content.sh --check all compare compiled output against apm.yml, so
their job is to propagate whatever it says byte-for-byte. The wiki claim passed
all fourteen pre-push hooks every day it was published. Enumeration also makes a
marketplace release the consequence of a directory appearing.

Implementation notes:
- ADR-0021 records the decision, the three failures, and why no gate is added:
  the check is one-directional, cannot see an invented capability, and a
  correspondence map would relocate the same per-skill maintenance one file over.
- bin 1.1.4 -> 1.1.5, git 1.3.4 -> 1.3.5, gitea 1.3.5 -> 1.3.6,
  marketplace.version 0.4.4 -> 0.4.5, all PATCH under per_package.
- apm.yml's top-level version: is restored to lockstep at 0.4.5. It has moved
  with marketplace.version in all eleven commits that ever touched the file
  until this branch left it at 0.4.2, and apm.yml's own comment records it as
  live and consumed by apm audit.
- git's boundary names the pre-commit hooks explicitly: pc-author and pc-run are
  not git operations, and a boundary drawn narrower than the contents is the
  same defect one level up.
- Regenerated with apm pack for the marketplace manifests and
  sync-plugin-content.sh --all for the per-plugin ones; both mirrors verified
  byte-identical.

Impact: consumer-facing. 16/16 pre-push hooks pass, suite green, generated diff
is 26 insertions and 26 deletions across 8 files with no incidental churn.

Refs: #105
ADR: 0021

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TmFqzpuExLJv3m114XVE9w
2026-08-17 12:28:55 +00:00
de84d1b677 chore(apm): give bin a published description that describes it
Why: bin's marketplace description read "A place for things to be binned" — a
routing boundary sitting in the enumeration slot, phrased as a joke. It is what
a consumer sees in the marketplace listing for a plugin shipping eleven
substantive skills: research, write-docs, tdd, prototype, triage, diagnose,
improve-codebase-architecture, grill-me, grill-with-docs, zoom-out and caveman.

This is the same category error b0ef503 fixed for git and gitea, and the same
text bb9158d moved out of core's description in August — "triage, diagnosis,
architecture review" left core precisely because those skills live in bin, so
bin is where it should have landed.

Implementation notes: bin 1.1.3 -> 1.1.4, marketplace 0.4.3 -> 0.4.4, PATCH for
metadata under the per_package strategy. README's bin line mirrors the new
description. architecture.md's routing boundary is deliberately left as
"unsorted skills that have not earned a home yet" — that is still true, and it
answers a different question than the listing does.

Impact: consumer-facing. apm-pack-check-clean, check-plugin-content-sync,
check-marketplace-mirror-sync, validate-marketplace, validate-plugins and
apm-audit-ci all pass.
2026-08-17 10:33:25 +00:00
65bac15257 chore(apm): correct git and gitea published descriptions and regenerate
Why: both plugins' published descriptions named capabilities that do not exist
and omitted ones that do. `gitea` advertised wikis — no wiki skill exists and
`grep -ri wiki plugins/gitea/.apm/` is empty — while omitting gitea-branches and
gitea-files. `git` advertised pull requests, which are gitea's, while omitting
pc-author/pc-run, git-submodules and git-workflow. These are compiled into
plugin.json and both marketplace.json files, so they are published metadata, not
internal notes.

This is the same defect bb9158d fixed on `core` in August, so the fix follows
that precedent exactly: correct the package apm.yml and the root marketplace
entry together — fixing only the package manifest leaves it half-propagated,
since the root entry is what reaches the compiled marketplace.

Implementation notes:
- git 1.3.3 -> 1.3.4, gitea 1.3.4 -> 1.3.5, marketplace 0.4.2 -> 0.4.3, all
  PATCH for metadata under the per_package strategy at apm.yml:76.
- Regenerated with `apm pack` for the two marketplace manifests and
  `scripts/sync-plugin-content.sh --all` for the four per-plugin plugin.json
  files; `apm pack` alone does not touch those. `scripts/sync-marketplace-mirror.sh`
  refreshed the Copilot legacy mirror, which no apm profile targets.
- README's gitea line mirrors the new published description. The routing
  boundaries in architecture.md deliberately do not, since they answer a
  different question.

Impact: consumer-facing. Anyone reading the marketplace now sees what these
plugins ship. apm-pack-check-clean, check-plugin-content-sync,
check-marketplace-mirror-sync, validate-marketplace and apm-audit-ci all pass.
2026-08-17 10:13:31 +00:00