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: at484357athe 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 at598a7c3, 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
9.8 KiB
name, description
| name | description |
|---|---|
| AI Development Repo | The domain language of the global AI development config repository |
AI Development Repo
The bounded context of this repo is how agent instructions are authored, packaged, distributed, and
kept small. Terms here name concepts specific to that problem. Mechanics live elsewhere:
docs/spec/architecture.md for structure, docs/spec/gates.md for enforcement, docs/adr/ for
decisions.
Language
Context cost
Routing target:
The skill or agent name a boundary clause sends work to. It resolves when a skill or agent of
that name is reachable from the file being checked, and dangles when none is — a route the router
cannot take. Dangling is a blocking ERROR in route notation (/name, → name) and a SUGGESTION for
a bare name nothing else in the sentence corroborates. Verdicts and the resolution walk:
docs/spec/gates.md.
Avoid: route, pointer, cross-reference
Dispatch body:
The body pattern a skill with two or more mutually exclusive flows must use — the body carries only
the dispatch table and the gates common to every branch, and each flow lives in its own
self-contained references/ file. Exemplar: apm-workflow.
Avoid: router body, thin body
Hand-invoked skill:
A skill reached only by typing its slash command, declared disable-model-invocation: true. The host
withholds it from the model-visible listing entirely, so it pays no preload tax and its description
becomes human-facing text. The flag also hard-blocks the Skill tool, so no other skill can route to
a hand-invoked skill — a Call `x` step in another skill's body stops working the moment x
takes the flag. Check inbound routes before declaring one. Exemplar: zoom-out.
Avoid: manual skill, disabled skill
Delegation discipline:
The agent-side counterpart to the dispatch body. A plugin-scope agent is a single .agent.md file
with no sibling references/ directory, so it cannot disclose to itself — it can only delegate to
skills. Its characteristic defect is therefore restatement, not length.
Avoid: agent hygiene
Distribution
Skill:
A reusable slash command defined as a SKILL.md file following the
Agent Skills open standard, authored at
plugins/<plugin>/.apm/skills/<skill>/SKILL.md.
Avoid: command, prompt, macro
apm package:
The deployable unit apm builds and installs — one or more skills, agents, hooks, commands, and MCP
servers under a single directory plugins/<name>/, consisting of that directory's apm.yml plus
the hand-authored plugins/<name>/.apm/ tree it deploys from (ADR-0015).
Avoid: bundle, module, source tree; and bare "plugin" for the installable artifact, which since
ADR-0024 is an apm package and not a Claude Code plugin. "Plugin" stays correct as a modifier in the
repo's settled compounds — Plugin marketplace, "plugin units", plugins/.
Output profile:
A named ecosystem format apm pack can compile the marketplace manifest into, declared per profile
under root apm.yml's marketplace.outputs:. apm defines claude and codex; each writes to its
own default path unless overridden. Mechanics: docs/spec/architecture.md.
Avoid: build target, export format
Plugin marketplace:
A Git repository carrying a marketplace.json manifest that lists installable plugins. There is no
backend, registry, or SaaS — the Git repo is the marketplace.
Avoid: registry, store, catalogue
holocron: This repository, in its role as a plugin marketplace and as the remote the six plugin dependencies resolve against. Avoid: the marketplace, upstream
Provenance chain:
The three-stage traceability record linking a skill back to its research inputs: /research produces
topic docs and a sources.md; the author skill records which sources informed which files in
references/sources.md and source_keys frontmatter; factory-audit validates the chain is complete
and internally consistent.
Avoid: sources, citations, attribution
Governance
HITL (human-in-the-loop): The agent pauses before a consequential action and a human approves before execution. Required for irreversible or high-stakes actions — architecture changes, production deployments, security configuration. Avoid: manual approval, gated action
Documents
AGENTS.md:
The provider-agnostic always-on instruction file, in plain markdown with no provider-specific syntax
(ADR-0003). Two exist: repo-level, and the global core/AGENTS.md deployed to ~/.agents/AGENTS.md.
Avoid: instructions file, system prompt
Thin adapter:
A provider-specific instruction file (CLAUDE.md, .cursor/rules/*.mdc, copilot-instructions.md)
that imports its AGENTS.md and adds only that provider's syntax, carrying no original always-on
content of its own (ADR-0002, ADR-0003).
Avoid: wrapper, shim, provider file
LESSONS.md: The long-loop feedback log for patterns observed across sessions, at the repo root. Avoid: changelog, retro, postmortem
Quality
Skill composition: A skill calling another skill by name to delegate a sub-task — the caller owns the orchestration decision ("when to do X"), the callee owns the mechanics ("how to do X"). Avoid: chaining, nesting, sub-skill
Authoring root:
The directory a gate resolves against — the nearest ancestor of the file being checked holding
plugins/*/.apm/skills or plugins/*/.apm/agents, falling back to the nearest ancestor holding
.git. The walk: docs/spec/gates.md.
Avoid: repo root, project root
Near-miss:
A query that shares keywords with this skill but needs a different one — and, by extension, the
sibling that would wrongly answer it; boundary clauses exist to exclude genuine near-misses rather
than to enumerate siblings. Detail: factory-audit/references/skill-description-quality.md.
Avoid: overlap, similar skill
Issue: The cross-provider term for a tracked unit of work. Gitea is this repo's canonical tracker (ADR-0007), but skills say "linked issue" generically rather than naming a provider. Avoid: ticket, card, task
Family prefix:
The shared first segment of a skill name (git-, gitea-, apm-, agentsmd-) marking a group of
siblings. No bare skill name is a Family prefix of another: forge exists, so no skill is named
forge-*, because a prefix that matches a live sibling reads as ownership rather than membership.
Avoid: namespace, category
Relationships
- An apm package bundles one or more Skills and agents; a Plugin marketplace lists apm packages; holocron is this repo wearing that hat.
- AGENTS.md is the source of always-on rules; a Thin adapter imports it and originates nothing.
- Skill composition is the caller/callee split.
forgeroutes a genuinely undecided artifact type to the matching author skill — an already-specified fix (file, line, and change known) calls that author skill directly, because each routing hop re-derives instructions from a shorter brief and has been observed to drop hard constraints handed down the chain. - A Skill built on research carries a Provenance chain;
factory-auditfails it when broken. - LESSONS.md feeds the standing files: three or more entries on one pattern graduate the pattern into the relevant standing document.
Example dialogue
Dev: "This one only fires when someone types the slash command. Does its description still need trigger words?" Maintainer: "No — that's a hand-invoked skill. The host withholds it from the model-visible listing, so it pays no preload tax at all and the description is human-facing text." Dev: "Then the body can be as long as it needs to be?" Maintainer: "Different budget. The skill context contract gates the body whether or not the skill is model-invoked — the description competes with every other skill's description, the body competes with the caller's live conversation. Four mutually exclusive flows means a dispatch body: table in
SKILL.md, onereferences/file per flow." Dev: "And if I split it into an agent instead?" Maintainer: "Then you're in delegation discipline territory. An agent has noreferences/to disclose to, so the failure mode flips — it stops being length and starts being restatement of a procedure some skill already owns."
Flagged ambiguities
- "skill" was used for both the authored
SKILL.mdunderplugins/<name>/.apm/skills/and the deployed copy under.claude/skills/— resolved: the authoring source is the Skill; the deployed copy is gitignoredapm installoutput and is never edited. - Skills can answer to two names, bare (
gitea-prs) and namespaced (gitea:gitea-prs), depending on whether a native install exists at user scope alongside the apm one (ADR-0018) — resolved: write the bare name, which is the only formapm installproduces. - "plugin" was used both for the installable artifact under
plugins/<name>/and as a modifier in settled compounds (Plugin marketplace, "plugin units", theplugins/directory itself) — resolved: the installable artifact is an apm package, because ADR-0024 ended nativeclaude plugin installsupport and it is no longer a Claude Code plugin in any operative sense; the compounds keep the word and are not being renamed. - "context" means both the model's live token window and the bounded domain this file describes — resolved: unqualified "context" in this repo means the token window.
- "audit" was used for both an author skill's inline closeout and the audit skill's independent
clean-context recheck — resolved: these are two distinct layers, kept separate precisely because
an audit running in the same context as the work it checks shares that work's blind spots. The
recheck belongs to
factory-audit, not toforge, which routes only to the author skills and never to an audit.