The ADR-0020 boundary resolver (boundary_targets()/unresolved_targets()) only ever read a SKILL.md's description. A target named in the BODY -- a dispatch table row, a "run X" step, both routine in a 900-word procedure -- was checked by nothing. Two real instances shipped before either was caught by reading rather than by a gate: bin/write-docs routed twice to a deleted `to-prd` skill, and bin/triage told an agent to run a nonexistent `/setup-matt-pocock-skills` (both fixed in 03abcff; that fix was the symptom, this gate is the actual ask per #124). Added a separate, narrower extractor -- body_targets() / unresolved_body_targets() in the shared lib-boundary-resolver.sh -- rather than reusing the description resolver at wider scope. The description gate's sentence-level heuristics (BOUNDARY_MARKER, the follower test, in-sentence corroboration) are tuned for a one-to-three-sentence routing clause and misfire on dispatch-table/procedure prose in both directions, so the body gate reads only explicit route notation (`/name`, backticked-or-slash-prefixed `-> name` / `-> name`), already the description gate's own unconditionally-blocking tier. Three guards were added after running the extractor over the real 39-skill corpus and reading every hit rather than assuming the design was correct: - a target must be hyphenated, even in notation -- single-word citations like `/fork` (forge, citing Claude Code's own /fork command) and `/name` (skill-author, a placeholder) are not routes. - a bare hyphenated word after any arrow is not notation -- only ARROW_MARKED (backticked/slash-prefixed) is used, not NOTATION_ARROW's bare form, so ordinary process-chain prose ("prop -> new ref -> re-render", caveman) is not read as a route. - a name immediately preceded by `<` is a closing tag (`</what-to-do>`, grill-with-docs), not /name notation. Wired into both consumers that must agree by contract: scripts/ skill-size-check.sh (the pre-commit hook) and factory-audit's lib-checks-skill.sh (the audit). Verified identical findings across both over the whole corpus. tests/test-adr0020-targets.sh gains a dedicated section pinning the two live true positives and all three guards. docs/spec/gates.md and ADR-0020 get a matching amendment. Fixes: #124 ADR: 0020 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
kyberforge
Skills and agents for creating, maintaining, and managing a Claude Code / Copilot CLI plugin marketplace.
Install
apm is the only supported install path (ADR-0024). Declare this package in the consuming project's apm.yml:
dependencies:
apm:
- git: git@git.dev.rkdr.net:Defame1297/holocron.git
path: plugins/kyberforge
Then:
apm install
The entry above is unpinned and tracks the remote's default branch — add ref: <tag> to pin a release. Registering the catalogue instead (apm marketplace add git@git.dev.rkdr.net:Defame1297/holocron.git --name holocron) gets you the kyberforge@holocron short name, but writes to ~/.apm/marketplaces.json at user scope; the git+path object needs nothing beyond the manifest.
Native plugin installs do not work. This package ships no per-plugin manifest and no flat content directories, so a host that installs it natively gets zero skills, agents and hooks — and Claude Code raises no error while doing it (ADR-0024).
Contents
Authoring source lives in .apm/; it is the only content source and the only thing apm install deploys (ADR-0024).
| Component | Path | Description |
|---|---|---|
| Skills | .apm/skills/ |
Slash commands available after install |
| Agents | .apm/agents/*.agent.md |
Role-based agents; one vendor-neutral .agent.md per agent (ADR-0016) |
| Hooks | .apm/hooks/ |
Event-triggered automation — Claude Code only, see below |
Hooks are Claude Code-only. apm merges .apm/hooks/*.json into the consuming project's .claude/settings.json at install. Copilot CLI has no default hooks path — agents and skills default to agents/ and skills/, but hooks defaults to nothing (docs/research/docs/github-copilot-plugins/configuration.md:47), so Copilot reads hooks only via an explicit pointer in a plugin manifest — and since ADR-0024 there is no per-plugin manifest to carry one. Copilot therefore loads no hooks from this plugin. Details, including why a pointer was the wrong fix even when a manifest existed, are in docs/hooks.md.
Skills
| Skill | Description |
|---|---|
forge |
Grill an unclassified "I want to add something" request, decide whether it's a skill, agent, plugin, or marketplace entry, then route to the matching author skill |
skill-author |
Create or improve a skill from scratch, audit findings, or inline feedback |
agent-author |
Author an agent definition file |
factory-audit |
Audit a skill directory or an agent definition — structure, provider safety, description and body quality, and provenance; produces a findings report. Auto-detects which of the two it was handed (ADR-0025) |
apm-install |
Install or upgrade the apm CLI and set up the agent runtimes it drives (Copilot CLI, Codex, Gemini, generic llm) |
apm-workflow |
Author apm.yml, scaffold an apm package/marketplace, install dependencies, and compile/pack/publish/audit apm content |
Pre-commit tooling (pc-author, pc-run) lives in the git plugin, not here.
Author
Defame1297