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
This commit is contained in:
2026-09-15 18:39:43 +00:00
parent a5962ba773
commit 620f20b0fd
119 changed files with 6308 additions and 5487 deletions

View File

@@ -0,0 +1,105 @@
---
source_keys:
- context7-websites-code-claude
- claude-code-plugins-docs
- claude-code-subagents-docs
- context7-github-en-copilot
- github-custom-agents-configuration
---
# Body, Delegation and Comment Discipline Reference
Upstream source: Claude Code subagent and plugin references, GitHub Copilot custom-agents
configuration. House contract: the context budget.
Read this when judging the **body**, **delegation** and **comment-discipline** dimensions.
## The core test
For every sentence in the body, ask: **"Would the agent get this wrong without this instruction?"**
If no — cut it. The agent already knows it from general training. Adding it wastes tokens and
dilutes the signal of what matters.
## Agents take no body word gate
A skill body is gated at 600 words SUGGESTION / 900 FAIL; an agent body is deliberately gated at
nothing. The two are not the same construct: a skill body is loaded into the caller's live
context and competes with the conversation already there, while an agent body *becomes* the system
prompt of a fresh context that has nothing else in it. The rationale for the 900-word ceiling does
not transfer, so:
- **Never report an agent body as too long on a word count.** There is no number to cite.
- **Never add such a gate to `scripts/validate.sh`.** `tests/validate-agent.bats` pins its absence with a
body far past 900 words that must still pass, and adding one would contradict the ADR.
- The one length signal that does apply is the Copilot runtime's 30,000-character body limit, which
`validate.sh` already reports as a SUGGESTION because content past it is silently truncated.
Length is judged through the delegation check below instead, which is the defect a word count was
standing in for anyway.
## The delegation check
A plugin-scope agent is a single `.apm/agents/<name>.agent.md` file with no sibling `references/`
directory. It cannot progressively disclose to itself — it can only delegate to skills. So a
procedure spelled out in an agent body that a skill the agent invokes already owns is not a
shortcut: it is a second copy of that procedure, and the second copy drifts. This is the
characteristic agent defect, the way a stale README row is the characteristic skill defect.
**An agent body that restates a procedure owned by a skill it can invoke is a FAIL.** The Fix is
always the same shape: invoke `<skill>` instead.
How to apply it: for each procedural block in the body — a rule list, a numbered sequence, a
constraint table — ask which skill owns that procedure. If the agent names that skill anywhere (its
dispatch table, its routing prose, its frontmatter), the block is a restatement and the skill is
already there to be invoked.
Worked example. The three `*-orchestrate` agents exist to compose domain skills — `git-orchestrate`
(933 body words), `gitea-orchestrate` (1,199) and `apm-orchestrate` (1,080) — so any step they
spell out that the composed skill already owns is the defect. `git-orchestrate:24-31` carries a
"Hard rules" list (Conventional Commits types, atomic commits, never commit secrets, git trailers)
that `git-commits` owns and that `git-orchestrate:44` routes to by name; `:39` concedes the point
outright, noting the sub-skills "carry their own local copies of these rules". Two copies, one
authority, and nothing keeping them in step.
What is **not** a finding under this rule, because no skill owns it:
- The dispatch table itself — which operation routes to which skill.
- Safety gates the agent enforces before dispatching, and refusals it makes on its own authority.
- The input contract and the structured output the agent's caller consumes.
- Session state the agent carries across skill invocations.
## What the body is for
Include what the fresh context lacks:
- A direct role instruction opening the prompt: `You are a [role]. When invoked, [action].`
- One bounded job, stated so the agent knows what it must refuse.
- The dispatch, gates, inputs and outputs listed above.
- **Error handling** — what the agent does on malformed, missing or contradictory input: stop and
report, or degrade to a named fallback. Absent it, the agent invents a recovery, and a
subagent's invented recovery is invisible to its caller until the output is wrong.
- Non-obvious environment facts and project-specific conventions it cannot infer.
- One default per decision point with one escape hatch.
Do not include at all:
- Concepts the agent already knows (what JSON is, how HTTP works, what a CSV is)
- Exhaustive option lists — pick a default; the agent does not benefit from choosing
- Steps the agent handles independently — over-specifying leads to unproductive paths
- Restatements of the description, which is already in context
## Comment discipline
Inspect every comment block in the YAML frontmatter and apply the core test to each: *would the
agent get this wrong without this comment?* Template scaffolding — `# Optional. <long
explanation>`, more than a line or two of inline guidance per field — belongs to development, not
to a shipped file. At plugin/APM scope the stakes are higher than tidiness: `apm compile` copies
frontmatter verbatim to every target, `<!-- ... -->` is not valid YAML, and `validate.sh` FAILs a
frontmatter block that still contains one.
## Where the criteria live
Every FAIL and SUGGESTION criterion for these dimensions is in `references/agent-finding-criteria.md`,
which Step 3 reads on every run. This file is the reasoning behind them, loaded only when that file
puts the body, delegation or comment-discipline dimension in play.

View File

@@ -0,0 +1,96 @@
---
source_keys:
- context7-websites-code-claude
- claude-code-subagents-docs
- context7-github-en-copilot
- github-custom-agents-configuration
---
# Agent Description Quality Reference
Upstream source: Claude Code subagent reference, GitHub Copilot custom-agents configuration.
House contract: the context budget. The house contract is narrower than either
platform's schema rather than a reinterpretation of it: where both speak, both must be satisfied.
## Why the description is the expensive part
At startup an agent loads only the `name` and `description` of every installed skill and agent.
The body is never seen until the agent is invoked. The description therefore carries the entire
triggering burden **and** is paid for in every session, whether the agent fires or not.
A second cost is less obvious and is a correctness hazard rather than a token cost: a description
that summarises the workflow is a shortcut the caller takes *instead of* reading the body. A
measured failure upstream — a description saying "code review between tasks" — produced one review
where the body's flowchart specified two.
## Step 0 — establish which contract applies
Read the frontmatter before judging a single word.
- **`disable-model-invocation: true`** — the agent is hand-invoked. Its description is never
matched against user intent, so it is not a routing string. It carries **one plain human-facing
sentence** stating what the agent does. Audit it for that and nothing else. Reporting a missing
trigger clause, a missing boundary clause or absent indirect triggers on a hand-invoked agent is a
wrong finding, not a strict one. The field is Copilot-only and not on the vendor-neutral APM
allowlist, so this case arises in a Copilot `.agent.md` at project/user scope and nowhere else.
Its Claude Code counterpart has no equivalent field and stays model-invoked, so the two halves of
the pair carrying differently shaped descriptions is expected there rather than a
pair-consistency finding.
`user-invocable: false` does not belong in this bullet. The two are separate fields with opposite
defaults — `disable-model-invocation` (default `false`) governs runtime auto-selection,
`user-invocable` (default `true`) governs manual invocation, and the retired `infer` field was
replaced by the pair rather than by either one. So `user-invocable: false` says nothing about
whether the agent is model-routed: judge that from `disable-model-invocation` alone, and where
that is absent the three-part shape below still applies. `user-invocable` carries no
description-quality contract of its own and is out of this file's scope entirely.
- **No such flag** — the agent is model-invoked and the rest of this file applies.
## The three-part shape
A model-invoked description carries exactly three things:
1. **Trigger clause.** When to invoke, phrased imperatively: `Use when ...`. Not `This agent ...` —
the caller is deciding whether to act, not reading a catalogue entry.
2. **At most one capability clause.** What it does, in one clause. Never an enumeration.
3. **Boundary clause.** Compressed form: `Not <thing> -> <skill-name>.` The target must resolve to
a real skill directory or agent file in the authoring source.
Everything else belongs in the body or in the plugin's `README.md`.
## Indirect triggers — conditional, never blanket
Add "even if the user doesn't say X" **only where the user's natural phrasing genuinely omits the
domain word.** True for the `gitea-*` family: people say "create an issue", not "create a Gitea
issue". False for `git-commits`: nobody asks for a commit without saying commit. A blanket
indirect-trigger clause on an agent whose domain word is unavoidable is padding charged to every
session.
## Near-miss exclusions
Add a boundary clause only where a sibling skill or agent could plausibly steal the activation. Use
strong near-misses — queries that share keywords but need something different — not weak ones. One
boundary clause per genuine near-miss; a list of four is enumeration wearing a boundary's clothes.
## Before / after
```yaml
# FAIL — a noun-phrase opener rather than a trigger, capability enumeration in
# place of one capability clause, and no boundary clause at all, preloaded into
# every session forever. (The live git-orchestrate description, 254 chars.)
description: Orchestrates git workflow operations for other agents. Invoke when a
caller needs a multi-step or destructive git operation (rebase, force-push, branch
deletion) coordinated across domain skills with safety gates, session context, and
structured results.
# PASS — trigger, one capability clause, boundary. The operation list and the
# safety-gate mechanics are the body's job; the router cannot act on them.
description: >
Use when an agent caller needs a multi-step or destructive git operation
dispatched and safety-gated. Not conversational git help -> git-workflow.
```
## Where the criteria live
Every FAIL and SUGGESTION criterion for this dimension is in `references/agent-finding-criteria.md`,
which Step 3 reads on every run. This file is the reasoning behind them, loaded only when that file
puts the description dimension in play.

View File

@@ -0,0 +1,49 @@
---
source_keys:
- context7-websites-code-claude
- claude-code-plugins-docs
- claude-code-subagents-docs
- context7-github-en-copilot
- github-custom-agents-configuration
---
## claude-code-fields
name description tools disallowedTools model effort maxTurns permissionMode skills mcpServers hooks memory background isolation color initialPrompt
## claude-code-only-fields
maxTurns isolation memory permissionMode effort hooks mcpServers disallowedTools skills initialPrompt color background
## copilot-fields
name description tools target model disable-model-invocation user-invocable mcp-servers metadata
## copilot-only-fields
target disable-model-invocation user-invocable mcp-servers metadata
## apm-agent-allowlist
name description model source_keys disallowedTools
Parsing note: `validate.sh` reads the **first** non-empty, non-`#`, non-`---` line under each
heading as a whitespace-separated token list, and stops there. Keep the token line immediately
below its heading; explanatory prose goes after it, as here.
Why `disallowedTools` is on a list that is otherwise vendor-neutral, when `tools` is not
(ADR-0016 and its 2026-08-14 amendment): the two are not symmetric. `tools` is an **allowlist**
whose vocabulary differs per harness — Claude Code names its own tools, Copilot CLI uses aliases
(`execute`/`read`/`edit`/`search`/`agent`/`web`) — so a value correct for one is wrong for the
other, and `apm compile` copies frontmatter verbatim with no per-target integrator to reconcile
them. `disallowedTools` is a **denylist**, and denying by name is safe under verbatim copy: a name
the other harness does not recognise denies nothing, so the worst case is that the fence is absent
there, never that the wrong capability is granted. Claude Code honours it for plugin subagents: its
plugin agent-definition reference names the fields plugin agents silently ignore (`hooks`,
`mcpServers`, `permissionMode`), and `disallowedTools` is not among them.
`disallowedTools` also appears in `claude-code-only-fields` above, and that stays correct: at
project/user scope it is still a Claude-only field and must not appear in a Copilot `.agent.md`.
The two lists answer different questions — "may this field cross the CC/Copilot file boundary" for
a real pair, versus "is this field safe under verbatim copy to every target" for a single
vendor-neutral APM file.

View File

@@ -0,0 +1,98 @@
---
source_keys:
- context7-websites-code-claude
- claude-code-plugins-docs
- claude-code-subagents-docs
- context7-github-en-copilot
- github-custom-agents-configuration
---
# Finding Criteria
Every FAIL and SUGGESTION criterion, for every qualitative dimension, and nothing else. The
reasoning each criterion stands on, its worked examples and its house rules stay in that
dimension's rubric, which Step 3 loads only for a dimension this file puts in play.
Two rules on using it:
- A criterion that plainly applies is a finding. Write it up citing file and line.
- A criterion that might apply, or whose call the wording here does not settle, is a reason to load
that dimension's rubric — never a reason to drop the candidate. This file decides which rubrics
to read; it does not settle a close call on its own.
## description — `references/agent-description-quality.md`
Flag as FAIL if:
- **Over 400 characters.** Measured on the folded YAML value, not the raw source lines.
`validate.sh` reports the number; do not re-derive it, but do point the Fix at what to cut. Agent
descriptions have no platform-documented ceiling of their own, so 400 is the only hard limit
there is — do not go looking for a backstop behind it.
- **Internal mechanics appear in the description.** Any of:
- capability enumeration or a feature list;
- output-format detail ("Produces a compact findings report with Why and Fix per finding");
- composition or architecture notes ("composes X rather than duplicating Y", "a cross-cutting
shared agent", "the human-facing entry point", "replaces the old flat invocation");
- implementation detail ("self-validates via a bundled deterministic script").
None of it can change a routing decision and all of it is preloaded.
`Kyberforge.CompositionNote` catches the common phrasings deterministically; the rest is
judgment. This is the rule that deflates a description, so apply it before reaching for length.
- **The same trigger stated twice in two registers** — a verb list, then the same verbs re-quoted
as user phrasings, usually in the same order. One register, whichever routes better.
- **Descriptive rather than imperative phrasing** (`This agent ...`, `This is the ...`).
`Kyberforge.DescriptionOpener` catches any opener matching `^This`.
- **Vague capabilities** ("helps with agents" where "audits an agent definition pair" was
available). `Kyberforge.VagueWording` catches the known filler; imprecision outside that list is
judgment.
- **`Use proactively` in a Copilot or vendor-neutral description.**
`KyberforgeCopilot.ProactivePhrase` catches it. The phrase steers the Claude Code runtime and
does nothing anywhere else, so in a `.agent.md` it is preloaded text that buys no behaviour.
- **Trigger-list, boundary or indirect-trigger content on a hand-invoked agent** — see Step 0 of
`references/agent-description-quality.md`.
Flag as SUGGESTION if:
- **Over 250 characters** but at or under 400. This tier is what moves the corpus average; the FAIL
tier only stops outliers. Report it rather than treating a 399-character description as clean.
- A near-miss exclusion is present but targets a weak near-miss.
- An indirect trigger is present and warranted but could name the omitted phrasing more precisely.
**An unresolved boundary target is not graded here.** `validate.sh` resolves boundary targets for
agent files at both scopes and tiers the verdict itself — route notation (`/name`, an arrow form)
is an ERROR, the bare prose form a SUGGESTION unless a second target in the same sentence resolves.
Step 1 has already filed it under `### Structure` at that tier. Take the script's verdict rather
than re-resolving the name by hand, and do not re-grade it under description: a hand-walk over a
different universe can contradict the script, and re-grading puts one target in the report twice.
What is left to judgment is semantic and the script cannot reach it: whether a target that *does*
resolve is the right sibling to exclude, and whether a clause naming no target at all ("examine the
files manually") should have named one.
## body, delegation and comment-discipline — `references/agent-body-and-delegation.md`
Flag as FAIL if:
- The body restates a procedure owned by a skill the agent can invoke — Fix: invoke `<skill>`
instead
- A sentence answers "no" to the core test — it is padding
- A decision point presents a menu of options with no default
- An instruction repeats content already in the description
- Frontmatter comments are template scaffolding rather than instruction, or are HTML comments at
plugin/APM scope
- A prescriptive sequence is used where flexibility is fine, or the reverse
Flag as SUGGESTION if:
- The body does not open with a direct role instruction
- The body specifies no error handling — nothing tells the agent what to do with malformed,
missing or contradictory input
- The job the agent describes is unbounded, or bounded only implicitly
- A rationale is missing from a rule the agent is expected to enforce — present but unexplained
- Comments are useful but verbose enough to bury the field they annotate
**Never report an agent body as too long on a word count.** A skill body is gated at 600/900 words;
an agent body is deliberately gated at nothing, because an agent body *becomes* the
system prompt of a fresh context rather than competing with a live conversation. No number exists
to cite. The one length signal that applies is the Copilot runtime's 30,000-character body limit,
which `validate.sh` already reports as a SUGGESTION. Length is judged through the delegation FAIL
above instead.

View File

@@ -0,0 +1,64 @@
---
source_keys:
- context7-websites-code-claude
- claude-code-plugins-docs
- claude-code-subagents-docs
- context7-github-en-copilot
- github-custom-agents-configuration
---
# Agent Flow
Steps 1 to 3 for an agent definition — the target Step 0 matched as a `*.agent.md` file, or as a
`.md` file whose immediate parent directory is `agents/`. Work them in order, then return to
`SKILL.md` Step 4 to report.
## Gotchas
- An agent takes the skill description gates (250 characters SUGGESTION, 400 FAIL) and **no body word gate at all**. Its body becomes the system prompt of a fresh context, so the 900-word skill ceiling does not transfer and no number exists to cite. Judge an over-long agent body through the delegation check.
- **Plugin/APM scope only:** provider safety means survival of a verbatim copy to every target, not Claude-Code-versus-Copilot field leakage — `references/agent-scope-plugin-apm.md` carries the contract.
## Step 1 — Deterministic checks
Resolve all three paths against this skill's own directory so they work from a repo checkout and an installed plugin cache alike. Run exactly:
```bash
bash scripts/validate.sh <agent-file>
bash scripts/validate-provenance.sh <agent-file>
bash scripts/vale-wrap.sh <agent-file> [<counterpart-file>]
```
`validate.sh` takes either half of a project/user-scope pair or the single plugin/APM-scope file, detects the provider from the extension and the scope by walking up, then checks required fields, kebab-case `name`, `FILL IN:` placeholders, template HTML comments left in frontmatter, the description budget (250 chars SUGGESTION, 400 FAIL, measured on the folded YAML value) and the fields that scope permits. Its findings become the `### Structure` dimension — its FAILs and its SUGGESTIONs both — except the ones the Step 2 scope contract re-routes.
If a validation script fails or cannot run — Bash denied, `python3` or `vale` absent, a `scripts/lib-*.sh` library or `references/agent-field-inventory.md` missing — read `references/agent-validation-scripts.md`; what these scripts measure is not reproducible by reading.
`validate-provenance.sh` prints nothing on success, so read its exit code before you read its silence. **0** is a genuine pass, including the silent exit 0 at project or user scope, where plugin-scope provenance does not apply. **1** means real findings: its FAILs and INFOs become a separate `### Provenance` dimension, and it emits Why and Fix itself — surface those verbatim. **2** means the check never ran — an unshaped or missing target, a missing script library, or a missing dependency, reason on stderr, no findings and often no stdout at all. On a 2, report `### Provenance` as unverified and quote the stderr reason; never grade it as a clean pass. `validate.sh` uses the same tiers: **1** is real findings, **2** is never ran — report that as `### Structure` unverified, never as a failure.
`vale-wrap.sh` applies the bundled `Kyberforge` style as a prefilter. Pass no `--config`; the wrapper locates its own. At project/user scope pass both files of the pair, not only the one you were handed. Every rule is graded `error`, so every alert is a FAIL. Report each one citing its rule ID, filed under the dimension it belongs to, and do not re-derive it by judgment:
| Rule | Dimension |
|---|---|
| `Kyberforge.DescriptionOpener`, `Kyberforge.CompositionNote`, `Kyberforge.VagueWording`, `KyberforgeCopilot.ProactivePhrase` | description |
| `Kyberforge.SentenceOpenerThereIs`, `Kyberforge.PaddingPhrase` | body |
## Step 2 — Read the agent and load its scope contract
Read the agent file end to end, and at project/user scope its counterpart too. A path containing `.apm/agents/` is plugin/APM scope; anything else is project or user scope. Each contract names the dimensions that apply there and where `validate.sh` findings other than Structure belong:
| Scope | Read |
|---|---|
| plugin/APM | `references/agent-scope-plugin-apm.md` |
| project, user | `references/agent-scope-project-user.md` |
## Step 3 — Qualitative audit
Read `references/agent-finding-criteria.md` first — every dimension's FAIL and SUGGESTION criteria. Load the rubric below only for a dimension the criteria put in play: one carrying a candidate finding, or one where the criterion alone does not settle the call.
| Dimension | Rubric |
|---|---|
| description | `references/agent-description-quality.md` |
| body, delegation, comment-discipline | `references/agent-body-and-delegation.md` |
Each rubric is the reasoning behind its criteria, not a second copy of them. Cite file and line number for every finding.
Then return to `SKILL.md` Step 4.

View File

@@ -0,0 +1,58 @@
---
source_keys:
- claude-code-plugins-docs
- claude-code-subagents-docs
- github-custom-agents-configuration
---
# Plugin/APM Scope Contract
Read this when the agent file sits at `<package>/.apm/agents/<name>.agent.md` — a single
vendor-neutral file inside an APM package, with no counterpart anywhere.
## What is different here
`apm compile` copies an agent's frontmatter **verbatim** to every target harness. There is no
per-target integrator to reconcile a Claude-Code-only field with a Copilot-only one, so the file
cannot carry either (ADR-0016). That single fact drives everything below.
## Frontmatter allowlist
The permitted keys are the `apm-agent-allowlist` section of `references/agent-field-inventory.md`. Read
them from there. Do not recite the list in a finding, do not work from memory, and do not trust any
restatement of it you find elsewhere in this repo: the list is data with one home (ADR-0009), it
has changed before, and `validate.sh` parses that same section at load time, so a recitation is a
copy that can disagree with the check the agent just ran.
`agent-field-inventory.md` records why a denylist-shaped field is admitted where an allowlist-shaped one
is not. Read that note before arguing with a finding about it.
## Dimension routing
`validate.sh` findings land as follows at this scope:
| Finding | Dimension |
|---|---|
| any frontmatter key outside the allowlist; body over the 30,000-character Copilot limit | Provider safety |
| everything else — missing or malformed field, `name` not matching the filename stem, empty body, absent frontmatter, template HTML comments, description length | Structure |
| — | Pair consistency never applies |
**Provider safety means something else here.** At project/user scope it asks whether a field leaked
across the Claude Code / Copilot boundary. At this scope there is no boundary and no pair: it asks
whether every field survives a verbatim copy to *every* target. Report it in those terms — a
finding phrased as "CC-only field in a Copilot file" is the wrong finding here.
**Pair consistency never applies.** There is one file by design. `validate.sh` never emits a
missing-counterpart FAIL at this scope, and neither do you, under any circumstance. Drop
`pair-consistency` from the Step 4 coverage line rather than reporting it clean.
## Behaviour the schema cannot express
Read the description and body. If either implies a need the vendor-neutral frontmatter can no
longer express — a tool restriction, `isolation`, `memory`, or another Claude-only behaviour a
hand-authored CC file could have declared — flag it as a **SUGGESTION, never a FAIL**. This is a
known upstream schema limitation (ADR-0016), not an authoring mistake, and the finding exists to
give the author visibility into the gap rather than to imply the schema can be made to close it.
Example: a body saying "only use Read and Grep, never Edit" with no `tools` field to enforce it.
A denylist-shaped restriction is the available half of that — see `agent-field-inventory.md`.

View File

@@ -0,0 +1,59 @@
---
source_keys:
- context7-websites-code-claude
- claude-code-subagents-docs
- context7-github-en-copilot
- github-custom-agents-configuration
---
# Project and User Scope Contract
Read this when the agent file is not under `.apm/agents/` — a Claude Code `.md` and Copilot CLI
`.agent.md` **pair**, at project scope (`<repo>/.claude/agents/` and `<repo>/.github/agents/`) or
user scope (`~/.claude/agents/` and `~/.copilot/agents/`). `validate.sh` derives the counterpart
from whichever half it was handed; audit both.
## The pair is a house convention
Neither platform requires a counterpart file. The pair is a kyberforge convention (ADR-0005), so a
missing counterpart is a FAIL against **this repo's** convention and must be labelled that way in
the finding, not presented as a platform spec failure.
## Dimension routing
`validate.sh` findings land as follows at these scopes:
| Finding | Dimension |
|---|---|
| a Claude-Code-only field in the Copilot file, a Copilot-only field in the CC file, a tool the runtime withholds from subagents, body over the 30,000-character Copilot limit | Provider safety |
| counterpart file not found | Pair consistency |
| everything else — missing or malformed field, name format, empty body, absent frontmatter, description length | Structure |
The two field lists are the `claude-code-only-fields` and `copilot-only-fields` sections of
`references/agent-field-inventory.md`. Read them from there rather than from memory; `validate.sh` parses
those same sections, so any restatement is a copy that can disagree with the check (ADR-0009).
## Field and naming rules that differ by provider
- `name` must match the filename stem in a **Copilot CLI** `.agent.md`. Claude Code imposes no such
rule, so a CC file whose `name` differs from its filename is not a finding.
- A Copilot **cloud/IDE** agent — one under `.github/copilot/agents/` — may omit `name` entirely.
If it carries one, it still has to be kebab-case.
- `Use proactively` is meaningful in a CC description and steers the runtime to offer the agent
unprompted. In a Copilot description it does nothing; `KyberforgeCopilot.ProactivePhrase` flags
it. The Copilot equivalent is `disable-model-invocation`, which changes the description contract
entirely — see `references/agent-description-quality.md`, Step 0.
## Pair consistency
Check that:
- Both files exist.
- Both system prompt bodies are non-empty (`validate.sh` covers this; do it by hand only when the
script could not run).
- The two files describe the **same job**. Divergent capability claims across the pair mean one
half was edited and the other was not, which is the defect this dimension exists to catch.
- Descriptions may legitimately differ in *shape* when the Copilot half is hand-invoked — that is
the Step 0 case in `references/agent-description-quality.md`, not a pair-consistency finding.
Keep `pair-consistency` in the Step 4 coverage line at these scopes.

View File

@@ -0,0 +1,76 @@
---
source_keys:
- claude-code-plugins-docs
- claude-code-subagents-docs
- github-custom-agents-configuration
---
# Validation Scripts Reference
Read this when a Step 1 script fails, cannot run, or reports something that needs interpreting.
Nothing here is needed on a clean run.
## Report the gap, do not guess
If a script cannot run at all — Bash denied, `python3` unavailable, `vale` not installed — say so
as an **INFO** finding naming the script and the missing dependency, then fall back to the manual
checks below. An INFO never changes PASS/FAIL. Silently omitting the dimension a script would have
covered reports a clean audit that checked less than it claims to have checked.
## How the scripts detect scope
`validate.sh` and `validate-provenance.sh` walk up from the agent file's directory and stop at the
first of these:
1. An `apm.yml` carrying a top-level `type: instructions|skill|hybrid|prompts` line — **plugin/APM
scope**, and that directory is the package root. An `apm.yml` with no `type:` is a
marketplace-only manifest: skip it and keep walking.
2. `$HOME` — **user scope**, checked before `.git` so a dotfiles-managed home directory that is its
own repo cannot shadow it.
3. A `.git` directory or file — **project scope**.
4. The filesystem root — **project scope**.
`plugin.json` and `.claude-plugin/plugin.json` are not scope signals. A directory holding only a
`plugin.json` and no `apm.yml` falls through to project or user scope.
`validate-provenance.sh` exits 0 silently when that walk does not land on a package root, and again
when the package has no provenance data. Check the exit code before you believe the silence:
- **0** — a pass, not a skip you need to investigate. Both silent cases above land here.
- **1** — real findings, on stdout with Why and Fix.
- **2** — the check never ran. A missing, doubled, non-file or wrongly-named argument, an
undecodable `apm.yml`, or an absent `python3`, each with a diagnostic on stderr and no findings
at all. Report the `### Provenance` dimension as unverified and quote the reason. An exit 2 is
never a clean pass: empty stdout there means nothing was checked, not that nothing was wrong.
## Manual fallback
**Every scope:** required fields present (`name`, `description`, non-empty body); `name` is
kebab-case; no `FILL IN:` placeholders in the description or body; the description at or under 400
characters measured on the folded YAML value.
**Plugin/APM scope:** `name` matches the filename stem; no HTML comments left in the frontmatter;
no frontmatter key outside the `apm-agent-allowlist` section of `references/agent-field-inventory.md` —
open that file, do not work from memory.
**Project/user scope:** the counterpart file exists; `name` matches the filename stem in the
Copilot `.agent.md` only (Claude Code files are exempt); no key from `claude-code-only-fields` in
the Copilot file and none from `copilot-only-fields` in the CC file, both read from
`references/agent-field-inventory.md`.
## Script-specific failures
- **`Error: agent-field-inventory.md not found` (exit 2).** `validate.sh` reads its field lists from
`references/agent-field-inventory.md` at load time and refuses to run without it, rather than falling
back to a hardcoded list that could disagree with the file (ADR-0009). Restore the file; do not
work around it.
- **`vale` reports `0 files`.** Treat the pass as NOT RUN, not as clean, and fall back to full
Step 3 judgment for the dimensions it would have covered. The `Kyberforge` style is scoped to
`**/agents/*.md` and `**/*.agent.md`, and `KyberforgeCopilot` to `**/*.agent.md` alone — a file
outside those globs is silently not linted.
- **`E100 Runtime error ... does not exist` (exit 2) from `vale-wrap.sh`.** An explicit relative
`--config` was passed. Pass none: the wrapper locates its own `assets/vale/.vale.ini` from its
own path. Do not read this exit code as vale being unavailable.
- **A path argument that does not exist is a hard error** in `vale-wrap.sh`, deliberately: bare
`vale` would fall back to reading stdin and print a clean-looking `0 errors ... in stdin`, which
the `0 files` guard above does not catch.

View File

@@ -0,0 +1,209 @@
---
source_keys:
- agentskills-spec
- agentskills-best-practices
---
# Body Discipline Reference
Upstream source: agentskills.io — skill-authoring, best-practices.
House contract: the context budget.
## The core test
For every sentence in the body, ask: **"Would the agent get this wrong without this instruction?"**
If no — cut it. The agent already knows it from general training. Adding it wastes tokens and
dilutes the signal of what matters.
## What the body is for
The body carries the **decision procedure only**: ordered steps, decision branches, gates, and
which reference to load when.
Include content the agent lacks:
- Project-specific conventions and domain procedures it cannot infer
- Non-obvious edge cases and environment-specific gotchas
- The specific tools or sequences to use — not the full range of options
- One default per decision point with one escape hatch
Move to `references/`, behind an explicit "If X, read `references/<file>.md`" trigger — the literal
conditional form, never a generic pointer. Write the real filename in the skill under audit; the
angle brackets are a placeholder here, and a literal `references/file.md` in a body is an ERROR
from the gate because no such file exists on disk.
**A dispatch table satisfies this requirement on its own.** A table row already pairs a condition
with a target, which is exactly what the literal form encodes; restating each row underneath as a
prose conditional duplicates the routing in the one body whose whole purpose is to be short. Where a
body dispatches, audit the table for condition/target completeness and stop there — do not require
the conditional form as well. The literal form is what a body needs when it loads a reference
*without* a dispatch table: a single mid-procedure deepening, an escape hatch, an error path.
Move:
- Lookup tables and spec restatements
- Output schemas, templates and example blocks
- Rationale and justification prose
- Anything only one branch of the procedure ever reaches
Do not include at all:
- Concepts the agent already knows (what JSON is, how HTTP works, what a CSV is)
- Exhaustive option lists — pick a default; the agent does not benefit from choosing
- Steps the agent handles independently — over-specifying leads to unproductive paths
- Restatements of the description, which is already in context
## Two length families, measured differently
Do not conflate these, and do not report them as one finding.
| Gate | SUGGESTION | FAIL | Counts |
|---|---|---|---|
| Body budget (house) | 600 words | 900 words | the **body only** — everything after the frontmatter's closing `---` |
| Spec conformance (agentskills.io) | — | 2,770 words / 500 lines | the **whole file**, frontmatter included |
The 2,770-word ceiling is a token-conformance backstop calibrated to the densest prose in the
corpus; it says nothing about quality and a file can sit a thousand words inside it while failing
the body budget. The 900-word ceiling is the quality gate: a body is loaded into the caller's live
context and competes with the conversation already there. `validate.sh` reports both. Cite whichever
one actually fired.
A word count cannot detect the defect it stands in for. Treat both numbers as backstops to the
dispatch rule and the Gotchas constraint below, never as a substitute for them.
## Dispatch is mandatory at two or more mutually exclusive flows
If a skill handles two or more flows that a single invocation cannot both take — separate
subcommands, separate input types, separate lifecycle stages — the body carries a **dispatch
table** plus the gates common to every branch, and each flow lives in its own self-contained
`references/` file. Inlining all of them is a FAIL regardless of word count, because every
invocation then pays for every branch it did not take.
The reference shape in this repo is `apm-workflow`: a **294-word body** dispatching to 3,154 words
of references across five mutually exclusive flows. Its whole-file count is 348 words — cite 294
when calibrating a body, or the conflation this section warns against reappears in the finding
itself. The 3,154 counts the five flow files only; `references/sources.md` is a provenance record
and is never loaded at runtime, so counting it inflates the dispatched total.
### What earns the wiring exemption
A dispatch table earns the exemption above on its properties, not on which skill it appears in.
Audit any dispatching body against these four:
- Every flow the skill handles has a row, and every row names a target file that exists on disk.
- Each row pairs a condition the agent can evaluate from the request with exactly one target. A row
keyed on a literal slash invocation fails this: a model-invoked activation never produces that
string, so the routing silently falls to whatever else the row carries.
- One line after the table tells the agent to read the file its row matched, and only that one.
- The gates every branch needs sit in the body, not inside one flow's file — see the reachability
precondition below.
A table missing any of the four is not exempt, and the literal-conditional requirement applies to it
as written. The exemption covers the wiring form only: every other rule in this file applies to a
dispatching skill exactly as it applies to any other.
## Gotchas sections
The highest-value construct in a body, and the easiest to fill with noise. A Gotcha must state a
fact that **contradicts a reasonable default** — something the agent gets wrong precisely by acting
sensibly.
```markdown
## Gotchas
- The `users` table uses soft deletes. Always include `WHERE deleted_at IS NULL`.
- User ID is `user_id` in the database, `uid` in auth, `accountId` in billing. Same value.
```
Constraints:
- **More than five entries is a SUGGESTION** — five is the guideline, not a ceiling. Past five, the
section is usually a summary of the body rather than a set of traps, and the agent stops reading
it as a warning. It stays advisory because whether a given gotcha earns its place is judgment;
`validate.sh` emits it through `suggest()` and the run still exits 0.
- **A Gotcha that paraphrases a step in the body below it is a FAIL.** It has no independent
content, and it teaches the agent that Gotchas can be skimmed because the real instruction is
coming. This one is the auditor's call — no script detects it. The Fix is conditional: delete the
Gotcha only if the surviving copy is reachable from every branch that needs it — see the
reachability precondition below.
- **A Gotchas section exceeding 25% of the body is a SUGGESTION** — the body has been inverted into
a preamble. Same tier and same reasoning as the entry count, and independent of it: either can
fire without the other.
- Place the section near the top. A gotcha read after the mistake is worthless, which is also why
Gotchas is the one construct exempt from moving to `references/`.
Worked negative example — **`git-commits` v0.1.2 at commit `5e23250`, a fixed pre-retrofit
snapshot, not the current file.** The live skill is v0.1.3 and matches none of the citations below;
they are quoted as they stood in that snapshot, and are not to be refreshed against
`HEAD`. The snapshot is reachable only from a checkout of the authoring repo — an installed plugin
cache holds no git history and no such path — so read the citations below as quoted rather than
going to look for the file. From a checkout:
```text
git show 5e23250:<the git plugin>/.apm/skills/git-commits/SKILL.md
```
That body carried twelve Gotchas, four of which restated content already below them or already in
the description:
| Gotcha | Restates |
|---|---|
| `:31` "SemVer mapping is not optional" | the description |
| `:32` "Confirmation gates are mandatory for destructive operations" | step 9 at `:52` |
| `:33` "Never skip hooks with `--no-verify`" | step 9 at `:52` |
| `:36` "Never commit secrets" | step 2 at `:45` |
All four are FAILs under the paraphrase rule. The entry count and the section's share of the body
(387 of 1,102 words, 35%) are two further SUGGESTIONs on top — the script reports both, and neither
fails the run on its own. What makes this worth auditing directly is that the four paraphrase FAILs
pass every word gate there is; only reading the construct finds them.
### The paraphrase rule has a reachability precondition
**A Gotcha that restates a step may be deleted only when the surviving copy is reachable from every
branch that needs it.** In a dispatch body it usually is not: each flow file is loaded alone, so a
step in one is invisible to an invocation that took another branch. When the restated rule is a
safety gate more than one flow needs, the Fix is to **move it into the body's common-gates section**,
never to drop it in favour of the per-flow copy.
Row four is the case that proves it. Following the rule literally, the retrofit deleted the
always-loaded secrets Gotcha and kept step 2 of `references/create-commit.md` — but `git-commits`
dispatches to exactly one flow file, and `references/rewrite-history.md` stages changes and runs
`--amend`, which commits newly staged content exactly as a fresh commit does. A grep for `secret`
across the skill in that state returned one hit, on a path two of three branches never reach: that
branch could commit a credential with no check anywhere in its loaded context, against this repo's
governance hard prohibition. v0.1.3 carries the rule as gate 2 of "Gates on every flow" instead.
So check reachability before writing the Fix. Rows one to three are unaffected — the description is
loaded on every invocation, and confirmation is likewise a common gate rather than a per-flow step.
## Calibrating control
**Be prescriptive** when operations are fragile, consistency matters, or a specific sequence must be
followed:
```markdown
Run exactly:
\`\`\`bash
python scripts/migrate.py --verify --backup
\`\`\`
Do not modify the command or add additional flags.
```
**Give freedom** when multiple approaches are valid. Explaining *why* outperforms rigid directives —
agents make better decisions when they understand the purpose.
## Defaults not menus
Never present a list of equivalent options — pick one and mention the alternative briefly:
```markdown
# Too many options
Use pypdf, pdfplumber, PyMuPDF, or pdf2image...
# Default with escape hatch
Use pdfplumber for text extraction. For scanned PDFs requiring OCR, use pdf2image instead.
```
The FAIL and SUGGESTION criteria for this dimension live in `references/skill-finding-criteria.md`,
which Step 3 loads on every run.

View File

@@ -0,0 +1,87 @@
---
source_keys:
- agentskills-spec
- agentskills-optimizing-descriptions
---
# Description Quality Reference
Upstream source: agentskills.io — optimizing-descriptions, specification.
House contract: the context budget. The house contract is narrower than the spec
rather than a reinterpretation of it: where both speak, both must be satisfied.
## Why the description is the expensive part
At startup an agent loads only the `name` and `description` of every installed skill. The body is
never seen until the skill triggers. The description therefore carries the entire triggering
burden **and** is paid for in every session, whether the skill fires or not.
A second cost is less obvious and is a correctness hazard rather than a token cost: a description
that summarises the workflow is a shortcut the agent takes *instead of* reading the body. A
measured failure upstream — a description saying "code review between tasks" — produced one review
where the body's flowchart specified two.
## Step 0 — establish which contract applies
Read the frontmatter before judging a single word.
- **`disable-model-invocation: true`** — the skill is hand-invoked. Its description is never
matched against user intent, so it is not a routing string. It carries **one plain human-facing
sentence** stating what the skill does. Audit it for that and nothing else. Reporting a missing
trigger clause, a missing boundary clause or absent indirect triggers on a hand-invoked skill is
a wrong finding, not a strict one.
- **No such flag** — the skill is model-invoked and the rest of this file applies.
## The three-part shape
A model-invoked description carries exactly three things:
1. **Trigger clause.** When to invoke, phrased imperatively: `Use when ...`. Not `This skill ...` —
the agent is deciding whether to act, not reading a catalogue entry.
2. **At most one capability clause.** What it does, in one clause. Never an enumeration.
3. **Boundary clause.** Compressed form: `Not <thing> -> <skill-name>.` The target must resolve to
a real skill directory or agent file in the authoring source. `validate.sh` checks that
deterministically and grades it by notation: an unresolved `/name` or arrow target is an ERROR
and reaches the report as a Structure FAIL, while an unresolved prose-form target ("use `y`
instead") is only a SUGGESTION unless a second target in the same sentence resolves. Take the
script's tier as given and report it once, under Structure.
Everything else belongs in the body or in `README.md`.
## Indirect triggers — conditional, never blanket
Add "even if the user doesn't say X" **only where the user's natural phrasing genuinely omits the
domain word.** True for the `gitea-*` family: people say "create an issue", not "create a Gitea
issue". False for `git-commits`: nobody asks for a commit without saying commit. A blanket
indirect-trigger clause on a skill whose domain word is unavoidable is padding charged to every
session.
## Near-miss exclusions
Add a boundary clause only where a sibling skill could plausibly steal the activation. Use strong
near-misses — queries that share keywords but need something different — not weak ones ("write a
fibonacci function"). One boundary clause per genuine near-miss; a list of four is enumeration
wearing a boundary's clothes.
## Before / after
```yaml
# FAIL — enumeration first, mechanics as the opener, a blanket indirect trigger,
# and 300+ characters of it preloaded into every session forever.
description: >
Analyze CSV and tabular data files — compute summary statistics, add derived
columns, generate charts, and clean messy data. Use when the user has a CSV,
TSV, or Excel file and wants to explore, transform, or visualize the data,
even if they don't explicitly mention "CSV" or "analysis."
# PASS — trigger, one capability clause, boundary. The four verbs the FAIL
# version enumerates are the body's job; the router cannot act on them.
description: >
Use when the user has a CSV, TSV, or Excel file and wants it explored,
transformed, or charted. Not schema design -> data-model.
```
(`data-model` is illustrative. In a real description the target has to resolve.)
The FAIL and SUGGESTION criteria for this dimension live in `references/skill-finding-criteria.md`,
which Step 3 loads on every run.

View File

@@ -0,0 +1,72 @@
---
source_keys:
- agentskills-spec
---
# File Structure and Internal Consistency Reference
Upstream source: agentskills.io — specification (optional directories, file references).
Read this when judging the **file-structure** and **internal-consistency** dimensions.
## Permitted directories
Only four: `scripts/`, `references/`, `assets/`, `tests/`. The specification permits additional
directories; this house does not, because an unlisted directory is content no auditor and no host
knows to look at. Flag any other directory as a FAIL.
- `scripts/` holds only executable code an agent can run, and the sourced libraries those entry
points load. A `lib-*.sh` that is never invoked on its own belongs here beside the entry point
that sources it — it is executable code, not documentation, so do not flag it for failing to run
standalone. Test files (`.bats`, `*_test.*`, `test_*.sh`) there are a FAIL — they belong in
`tests/`.
- No non-spec files at the skill root: no `META.md`, no stray config outside the four directories.
- An optional directory that exists must hold real content, not an unfilled placeholder README.
## Cross-plugin path references
A plugin is copied to a cache on install, and a path that climbs out of the skill directory stops
resolving there. Flag a path in `SKILL.md`, `scripts/`, `references/` or `assets/` when it
**resolves outside the skill directory** — an absolute repo path
(`plugins/<plugin>/skills/<other>/` and its APM-native equivalent `.apm/skills/<other>/`), a
plugin-root path (`docs/`, `bin/`), or a `../` chain that leaves the skill root.
Resolve before flagging, twice over:
- **Resolve the path.** `$SKILL_DIR/../assets/templates` climbs one level from a `scripts/`
directory and lands back inside the same skill, so it resolves in a cache install and is not a
finding. A bare `../` is not the defect; leaving the skill is.
- **Skip fenced code blocks.** A path inside a fenced block is an example, and rubrics quote outside
paths deliberately as negative examples of what not to write. Flag a fenced path only when the
surrounding prose presents it as the form to copy.
**Referring to another skill's file.** There is one sanctioned spelling, and it is possessive:
`skill-author's references/contract.md`. Write the skill by name and let the reader
resolve it — do not spell the repo path. The full path is the thing this section forbids, and
`references/contract.md` on its own is a hard ERROR from the gate, which
requires an unqualified `references/` pointer to exist in the skill's OWN directory. The
possessive form is the only spelling both rules accept; the gate recognises it and skips the
on-disk check. Flag any other spelling of a cross-skill reference.
Two directories are exempt, and the exemptions are structural rather than discretionary:
- **`references/sources.md`.** Its `Research doc:` fields are development-time provenance pointers,
not runtime references. They are expected to be unresolvable after install, so
`validate-provenance.sh` does not treat an absent path as a FAIL — it emits an INFO naming the
slug and stating that checks 7 and 8 did not run for it. Flagging them as broken references
would make every correctly-provenanced skill fail.
- **`tests/`.** Test files are dev-only and may reference repo-level infrastructure such as a shared
`tests/test_helper/`. The exemption is conditional on the dependency being declared: if `tests/`
exists and `tests/README.md` is absent or does not document it, that is a FAIL.
## Internal consistency
The skill has to agree with itself. Two checks:
- `SKILL.md`'s steps match what the scripts actually do — the arguments, the exit codes, and the
output shape it tells the agent to expect.
- Placeholder READMEs inside `scripts/`, `tests/` and `assets/` say the same thing about each
directory that `SKILL.md` does.
The FAIL and SUGGESTION criteria for this dimension live in `references/skill-finding-criteria.md`,
which Step 3 loads on every run.

View File

@@ -0,0 +1,136 @@
---
source_keys:
- agentskills-spec
- agentskills-best-practices
- agentskills-optimizing-descriptions
- agentskills-using-scripts
---
# Finding Criteria
Every FAIL and SUGGESTION criterion, for every qualitative dimension, and nothing else. The
reasoning each criterion stands on, its worked examples and its house rules stay in that
dimension's rubric, which Step 3 loads only for a dimension this file puts in play.
Two rules on using it:
- A criterion that plainly applies is a finding. Write it up citing file and line.
- A criterion that might apply, or whose call the wording here does not settle, is a reason to load
that dimension's rubric — never a reason to drop the candidate. This file decides which rubrics
to read; it does not settle a close call on its own.
## description — `references/skill-description-quality.md`
Flag as FAIL if:
- **Over 400 characters.** Measured on the folded YAML value, not the raw source lines.
`validate.sh` reports the number; do not re-derive it, but do point the Fix at what to cut.
- **Internal mechanics appear in the description.** Any of:
- capability enumeration or a feature list;
- output-format detail ("Produces a compact findings report with Why and Fix per finding");
- composition or architecture notes ("composes X rather than duplicating Y", "a cross-cutting
shared skill", "the human-facing entry point", "replaces the old flat invocation");
- implementation detail ("self-validates via a bundled deterministic script").
None of it can change a routing decision and all of it is preloaded.
`Kyberforge.CompositionNote` catches the common phrasings deterministically; the rest is
judgment. This is the rule that deflates a description, so apply it before reaching for length.
- **The same trigger stated twice in two registers** — a verb list, then the same verbs re-quoted
as user phrasings, usually in the same order. One register, whichever routes better.
- **Descriptive rather than imperative phrasing** (`This skill ...`, `This is the ...`).
`Kyberforge.DescriptionOpener` catches any opener matching `^This`.
- **Vague capabilities** ("helps with APIs" where "parses and validates OpenAPI specs" was
available). `Kyberforge.VagueWording` catches the known filler; imprecision outside that list is
judgment.
- **Trigger-list, boundary or indirect-trigger content on a hand-invoked skill** — see Step 0 of
`references/skill-description-quality.md`.
- **Over 1024 characters** — the agentskills.io specification ceiling, unchanged and independent
of the 400-character house ceiling above.
Flag as SUGGESTION if:
- **Over 250 characters** but at or under 400. This tier is what moves the corpus average; the FAIL
tier only stops outliers. Report it rather than treating a 399-character description as clean.
- A near-miss exclusion is present but targets a weak near-miss.
- An indirect trigger is present and warranted but could name the omitted phrasing more precisely.
**An unresolved boundary target is not graded here.** `validate.sh` owns that call and tiers it by
notation — `/name` or an arrow form is an ERROR, the bare prose form a SUGGESTION unless a second
target in the same sentence resolves — and Step 1 has already filed it under `### Structure` at that
tier. Re-grading it as a description FAIL puts one target in the report twice at two tiers. What is
left to judgment here is semantic and the script cannot reach it: whether a target that *does*
resolve is the right sibling to exclude, and whether a clause naming no target at all ("examine the
files manually") should have named one.
## body-discipline — `references/skill-body-discipline.md`
Flag as FAIL if:
- A sentence answers "no" to the core test — it is padding
- The body exceeds 900 words counted body-only (`validate.sh` reports it)
- Two or more mutually exclusive flows are inlined instead of dispatched
- A Gotcha paraphrases a step in the body below it that every branch reaching the Gotcha also
reaches
- A decision point presents a menu of options with no default
- An instruction repeats content already in the description
- A prescriptive sequence is used where flexibility is fine, or the reverse
Flag as SUGGESTION if:
- The body exceeds 600 words counted body-only but stays at or under 900
- The Gotchas section carries more than five entries
- The Gotchas section exceeds 25% of the body
- A rationale is missing from an include/exclude rule — present but unexplained
- Gotchas are correct but placed late in the body rather than near the top
- Content that only one branch reaches is inlined where a `references/` file would serve
## patterns — `references/skill-patterns.md`
Flag as FAIL if:
- A Gotcha entry is a general tip or a reminder rather than a fact that defies a reasonable
assumption
- An inner code fence is unescaped inside a markdown block, breaking the render
- A checklist wraps a single step
- A conditional reference gives no trigger — `Kyberforge.PaddingPhrase` reports the common form
- The agent must produce a specific format and no output template is given
Flag as SUGGESTION if:
- Gotchas are correctly formed but placed late in the body
- An output template is present but permissive where the consumer needs it exact
- A conditional reference names a trigger that is real but broader than the branch it guards
## file-structure and internal-consistency — `references/skill-file-structure.md`
Flag as FAIL if:
- A directory outside the four permitted ones exists
- Test files sit in `scripts/`
- A non-spec file sits at the skill root
- A path that resolves outside the skill directory appears outside the two exempt locations, in
prose rather than in a fenced example
- `tests/` exists but `tests/README.md` is missing or does not document its repo-level dependency
- `SKILL.md` describes a script invocation the script does not accept
Flag as SUGGESTION if:
- An optional directory exists but holds only a placeholder README
## formatting and scripts — `references/skill-formatting-and-scripts.md`
Flag as FAIL if:
- A script prompts interactively, in any form
- A script exposes no `--help`
- A destructive script has no `--dry-run`
- Data and diagnostics share a stream, so the output cannot be piped
- A relative path named in the body does not resolve
- Heading levels are inconsistent enough to break the document's structure
Flag as SUGGESTION if:
- Exit codes are meaningful but undocumented in `--help`
- A code block is untagged where a language applies
- A script is idempotent in practice but does not say so, leaving a re-run's safety unclear
- List indentation or section spacing is inconsistent without breaking the render

View File

@@ -0,0 +1,62 @@
---
source_keys:
- agentskills-home
- agentskills-spec
- agentskills-best-practices
- agentskills-optimizing-descriptions
- agentskills-using-scripts
---
# Skill Flow
Steps 1 to 3 for a skill directory — the target Step 0 matched as a directory containing
`SKILL.md`, or as a `SKILL.md` file, in which case `<skill-dir>` below is its parent directory.
Work them in order, then return to `SKILL.md` Step 4 to report.
## Gotchas
- A skill takes two independent length families, and it can sit inside one while failing the other — so report them separately. The 500-line / 2,770-word pair counts the **whole file** for spec conformance. The 250/400-character and 600/900-word pair is the house context budget, and its word half counts the **body only**.
## Step 1 — Deterministic checks
Resolve all three paths against this skill's own directory so they work from a repo checkout and an installed plugin cache alike. Run exactly:
```bash
bash scripts/validate.sh <skill-dir>
bash scripts/validate-provenance.sh <skill-dir>
bash scripts/vale-wrap.sh <skill-dir>/SKILL.md
```
`validate.sh` findings become the `### Structure` dimension — its FAILs and its SUGGESTIONs both, at the tier the script assigned. Report each once; never re-grade one under another dimension. Unresolved boundary targets are where this bites, because their tier turns on notation. It exits **0** when no check failed, **1** on real findings, and **2** when it never ran — an unshaped or missing target, a missing script library, or a missing dependency, reason on stderr. Report an exit 2 as `### Structure` unverified, quoting that reason, never as a failure or a pass.
Read `references/skill-validation-scripts.md` when any of the three cannot run or exits non-zero for a reason other than findings, **and whenever `validate-provenance.sh` exits 0 having printed anything**. Ordinary content FAILs are the expected outcome here and need no fallback.
`validate-provenance.sh` reports through exit code **and** output; neither alone is the verdict. **0, silent** is a genuine pass. **0 with output** is INFO-only findings — still a `### Provenance` dimension; `references/skill-validation-scripts.md` says what each obliges — for a check-9 INFO, reading rather than relaying. **1** is FAILs plus any INFOs; it emits Why and Fix itself — surface those verbatim. **2** means it never ran — an unshaped or missing target, a missing script library, or a missing dependency, reason on stderr, often no stdout — so report `### Provenance` unverified and quote that reason. Never grade an exit 2, or an exit 0 that printed, as a clean pass.
`vale-wrap.sh` applies the bundled `Kyberforge` style as a prefilter. Pass no `--config`; the wrapper locates its own. Every rule is graded `error`, so every alert is a FAIL. Report each one citing its rule ID, filed under the dimension it belongs to, and do not re-derive it by judgment:
| Rule | Dimension |
|---|---|
| `Kyberforge.DescriptionOpener`, `Kyberforge.CompositionNote`, `Kyberforge.VagueWording` | description |
| `Kyberforge.SentenceOpenerThereIs` | body-discipline |
| `Kyberforge.PaddingPhrase` | patterns |
## Step 2 — Read the whole skill
Read `SKILL.md` and every text file under `scripts/`, `references/`, `assets/` and `tests/`. Skip binaries only — internal-consistency findings need the full picture.
## Step 3 — Qualitative audit
Read `references/skill-finding-criteria.md` first — every dimension's FAIL and SUGGESTION criteria. Load the rubric below only for a dimension the criteria put in play: one carrying a candidate finding, or one where the criterion alone does not settle the call.
| Dimension | Rubric |
|---|---|
| description | `references/skill-description-quality.md` |
| body-discipline | `references/skill-body-discipline.md` |
| patterns | `references/skill-patterns.md` |
| file-structure, internal-consistency | `references/skill-file-structure.md` |
| formatting, scripts | `references/skill-formatting-and-scripts.md` |
Each rubric is self-contained and grounded in the agentskills.io specification plus the house context budget. Cite file and line number for every finding.
Then return to `SKILL.md` Step 4.

View File

@@ -0,0 +1,48 @@
---
source_keys:
- agentskills-spec
- agentskills-using-scripts
---
# Formatting and Scripts Reference
Upstream source: agentskills.io — specification (body content), using-scripts (designing scripts
for agentic use).
Read this when judging the **formatting** and **scripts** dimensions. Both are checklists of static
criteria that never vary by skill, which is exactly why they live here rather than in the body.
## Formatting
- Heading levels are consistent: H2 for main sections, H3 for subsections. A body that jumps from
H2 to H4, or opens on H3, reads as a fragment of a larger document.
- Code blocks carry a language tag wherever one applies — `bash`, `markdown`, `python`, `yaml`,
`text`. An untagged block loses syntax highlighting and, more importantly, loses the signal of
what the agent is meant to do with it.
- Whitespace is consistent: a blank line between sections, one list-indentation style throughout.
- No broken relative paths in file references. Every `references/…`, `scripts/…` and `assets/…`
path named in the body resolves against the skill directory.
## Scripts
A script in a skill is run by an agent with no terminal and no human to answer it. The criteria
follow from that:
- **No interactive TTY prompts** — no `read`, no `input()`, no `readline`. A script that blocks on
a prompt hangs the run with no diagnostic. `validate.sh` detects the common forms and reports
them under Structure; the judgment call is any prompt it cannot pattern-match. What counts is
where stdin comes from, not the word `read`: a `read` fed by a here-string, a here-doc, a pipe,
or a redirect from a file never touches a terminal and is not a finding. `validate.sh` excludes
those forms, so do not rewrite a working `read -r A B <<< "$line"` into parameter expansion to
satisfy this rule.
- **`--help` is exposed** and gives concise usage.
- **Data to stdout, diagnostics to stderr.** A caller piping the script has to be able to separate
the result from the commentary.
- **Idempotent** — "create if not exists" rather than "create", so a re-run after a partial failure
is safe.
- **Meaningful exit codes, documented in `--help`.** An agent branches on the exit code; an
undocumented one is a coin flip.
- **`--dry-run` present for destructive operations.**
The FAIL and SUGGESTION criteria for this dimension live in `references/skill-finding-criteria.md`,
which Step 3 loads on every run.

View File

@@ -0,0 +1,54 @@
---
source_keys:
- agentskills-spec
- agentskills-best-practices
---
# Patterns Reference
Upstream source: agentskills.io — best-practices (instruction patterns), specification.
Read this when judging the **patterns** dimension: whether each instruction construct a skill uses
is the right construct for the job and is correctly formed. Formation, not content — a Gotcha's
*content* is judged in `references/skill-body-discipline.md`.
## The constructs and when each is right
| Construct | Right when | Wrong when |
|---|---|---|
| Gotchas | An environment fact contradicts a reasonable default | Used as a summary of the steps below |
| Prescriptive sequence | The operation is fragile and flag order or exact arguments must not change | Several approaches are equally valid |
| Checklist | A multi-step workflow the agent must complete in order | A single step dressed up as a list |
| Conditional reference | Detail is needed on one branch only | The reference is needed on every run and is loaded blind |
| Output template | The agent must emit a specific format a caller consumes | The output is prose nobody parses |
## Formation rules
**Gotchas** sit near the top of the body, before the steps that would otherwise walk into them.
Placement late in the body is a SUGGESTION, not a FAIL — the content is still correct, it is just
read after the mistake.
**Prescriptive sequences** that quote a fenced block inside another markdown block must escape the
inner fence as `` \`\`\` ``. An unescaped inner fence terminates the outer block and the remaining
instructions render as prose.
**Conditional references** state a specific trigger, naming a file that exists in the skill's own
`references/` directory:
```text
If the API returns a non-200 status, read `references/api-errors.md`.
```
That block is fenced because the filename in it is illustrative — an unfenced `references/` pointer
in a `SKILL.md` body must resolve on disk or the gate reports a hard ERROR. The generic
form — pointing at the directory and hoping — defeats
progressive disclosure, because the agent either loads everything or loads nothing.
`Kyberforge.PaddingPhrase` catches the common generic phrasing deterministically; other malformed
forms are judgment.
**Output templates** belong in the body when the agent must emit them on every run, and in
`references/` when only one dispatch branch produces that output. A template inlined for a branch
most invocations never take is body-discipline padding.
The FAIL and SUGGESTION criteria for this dimension live in `references/skill-finding-criteria.md`,
which Step 3 loads on every run.

View File

@@ -0,0 +1,150 @@
---
source_keys:
- agentskills-spec
- agentskills-using-scripts
---
# Validation Scripts Reference
Read this when a Step 1 script fails, cannot run, or reports something that needs interpreting —
including `validate-provenance.sh` exiting **0 having printed something**, which is INFO findings,
not a clean run. Its silent exit 0 is the only outcome that needs nothing here.
## Report the gap, do not guess
If a script cannot run at all — Bash denied, `python3` unavailable, PyYAML not importable, `vale`
not installed — say so as an **INFO** finding naming the script and the missing dependency, then
fall back to the manual checks below. An INFO never changes PASS/FAIL. Silently omitting the
dimension a script would have covered reports a clean audit that checked less than it claims to
have checked, and the Step 4 coverage line then names a dimension nothing actually examined.
## Manual structural fallback
`validate.sh` needs `python3` **and** PyYAML, and refuses to start without either — the description
value has to be measured after YAML folding is resolved, so skipping these gates would be a
vacuous pass rather than a partial one. The two are checked separately, so the message already names
the right one — report it verbatim rather than diagnosing further:
```text
Error: python3 is required but was not found on PATH.
Error: PyYAML is required but is not importable by python3.
```
Without them — or with Bash denied, or on a permission error — work this list
by hand and file the results under `### Structure` exactly as the script's output would have been:
- **`name`** present, 1–64 characters, kebab-case (lowercase letters, digits and hyphens; no
leading, trailing or doubled hyphen), and **matching the skill's directory name** exactly.
- **`description`** present and non-empty; no unfilled `FILL IN:` placeholder in it. An absent or
empty description is a **FAIL**, never a silent skip — it is the one field preloaded into every
session, so a skill without one can never be routed to.
- **Description length**, measured on the folded YAML value with newlines collapsed to single
spaces — not on the raw block scalar, which counts indentation. 250 characters SUGGESTION, 400
FAIL (house), 1,024 FAIL (agentskills.io spec).
- **Body length**, counting everything after the frontmatter's closing `---`. 600 words
SUGGESTION, 900 FAIL (house).
- **Whole-file ceilings**, counting the file including frontmatter: 500 lines FAIL, 2,770 words
FAIL (agentskills.io spec). These are a different measurement from the two above — report them
as separate findings, never merged.
- **A boundary clause is present** — either the prose form (`do not` / `instead` / `rather than` /
`not for`) or the compressed `Not <thing> -> <name>` arrow. **SUGGESTION**, not FAIL:
the absence is deterministic, but whether this skill warrants one is the auditor's call.
- **Boundary targets resolve** — **FAIL** on a name that resolves to nothing. See the section
below; resolving these by hand is the one item on this list with a procedure of its own.
- **Every `references/<file>.md` named in the body exists on disk** — **FAIL**, not a suggestion.
A dispatch table or "read X" trigger naming a missing file sends the agent nowhere. Ignore
mentions inside fenced code blocks, and ignore a mention whose own line says the file is gone
(`removed`, `deleted`, `renamed`, `superseded`, `replaced`, `obsolete`, `deprecated`, `former`,
`gone`, `no longer`, `used to`) — that is a historical note, not a dispatch entry.
- **Gotchas discipline**, both **SUGGESTION**. Locate the section by a heading that *is* Gotchas
(`## Common Gotchas` counts; `## Gotcha handling` and `## Why gotchas matter` do not), running to
the next heading at the same level or shallower. More than five top-level entries is one
suggestion; a section over 25% of the body word count is a second, independent one. Count
entries at column 0 only — an indented child bullet is not an entry — and ignore fenced code
blocks for both.
- **No unfilled `FILL IN:` placeholder** anywhere in the body.
- **Every file in `scripts/`** carries the executable bit and contains no interactive prompt —
no bare `read`, no `select`, nothing that blocks on a TTY.
## Resolving boundary targets by hand
Targets are read from **both** boundary forms. The compressed `Not <thing> -> <name>` arrow and the
prose form are each parsed *and* target-checked, so a typo in prose phrasing fails exactly as an
arrow typo does — do not check only the names after an arrow.
Build the universe by walking up **from the `SKILL.md` under audit**, never from the validator's own
location. The nearest ancestor holding `plugins/*/.apm/skills/` or `plugins/*/.apm/agents/` is the
authoring root, falling back to the nearest ancestor holding `.git`. When one is found the universe
is every skill and agent under `<root>/plugins/*/`, plus the skill's own apm package, plus the
packages that package declares in its `apm.yml` under `dependencies.apm`. Deployed `.claude/` and
`.agents/` trees are consulted **only** when no authoring root exists — they are gitignored
`apm install` output, and reading them would make a fresh clone and a developer machine disagree.
Three ways to read the result wrong:
- **A hyphenated name used attributively is not a dangling target.** "Use pre-commit hooks instead
of ad-hoc scripts" reads as a route to `pre-commit` on wording alone. What separates a route from
prose is grammar: a route target is terminal — followed by punctuation, a conjunction, or a
boundary word — whereas a compound modifier is followed by the noun it modifies. A name followed
by an ordinary noun still *confirms* a route when it exists, but never raises a FAIL on its own.
- **A SUGGESTION-tier unresolved target is not a FAIL you may promote.** Terminal position alone is
not evidence of a route: "run `pre-commit` instead", "see `commit-msg`" and "use the clean-up
instead" are all terminal and all prose. A prose-form target earns a FAIL only when its own
sentence names another target that *does* resolve; otherwise the script reports it and moves on,
and so should you. Route notation — `/name` and `-> name` — is exempt and always FAILs, and it is
the fix to recommend when the author did mean a route.
- **`INFO boundary-target resolution DID NOT RUN` is not a pass.** The script prints it, and exits
0, when no universe could be determined for that path — the usual cause being a skill copy
audited outside its package. Report it as an INFO naming the unchecked targets and re-run against
the real directory; filing it as clean signs off targets nothing verified.
## Script-specific failures
- **`validate-provenance.sh` printed nothing *and exited 0*.** That is a pass, not a skip — it
exits 0 silently when the skill has no `source_keys` and no `references/sources.md`, and nothing
to validate is not a finding. Check the exit code before you believe the silence: a target that
is not a directory, a directory holding no `SKILL.md`, a missing or extra argument, and an absent
`python3` all exit **2** with a message on stderr. Exit 2 means the script never ran — report it
as an unaudited dimension, never as a pass and never as a finding. Exit 1 is findings.
- **A check-9 INFO — `'<field>' changed for '<slug>' since <ref>` — means go read, not just relay.**
Check 9 diffs the current `references/sources.md` against a base ref and flags a slug whose
`Description` or `Contributing files` text differs. It is structurally incapable of telling you
whether the new wording is still *true* — it only detects that the text changed — so when this
INFO fires, open that slug's own entry: the document named in its `Research doc:` field, and the
files its `Contributing files` list names. Read whichever the changed field is a claim *about* —
a Description-only change often leaves the file list untouched, so "open the Contributing files"
is where to look, not proof that they are what moved. Confirm by reading whether the (possibly
strengthened) claim genuinely holds. This is the one provenance finding this script cannot verify
for you: every other check here is a structural fact you can relay as-is, but check 9's job is
only to tell you *where* to spend that reading effort, not to replace it. Acknowledging the INFO
without opening those files is not auditing it. Its companion — `'<field>' removed for '<slug>'
since <ref>` — is the same obligation in the other direction: a claim withdrawn rather than
rewritten. No other check here requires the field, so confirm the removal was deliberate.
- **The check-9 base ref defaults to `git merge-base HEAD origin/main`, and there are two ways to
override it.** `--base-ref=<ref>` on the command line, or the `VALIDATE_PROVENANCE_BASE_REF`
environment variable; the flag wins when both are given, including when it is given empty
(`--base-ref=`), which selects the default resolution and ignores the environment. Reach for one
on a fork, a long-lived branch, or a mirror whose remote is not called `origin` — and when a
review asks what changed since a specific commit rather than since the branch point.
- **A single check-9 INFO naming a whole-check skip is an unaudited dimension, not a finding about
the skill.** There are three: "no repo root above the skill directory", "no base ref could be
resolved", and "`<path>` is not tracked at `<ref>`". The third is the one to read carefully — it
fires when the base ref resolved but `git show <ref>:<path>` did not, which covers both a
genuinely new `sources.md` (nothing to flag) and a path git does not know under that name: a
renamed skill directory, or an installed, gitignored copy such as a deployed `.claude/skills/`
tree. Auditing the deployed copy silently checks nothing; re-run against the authoring path under
`plugins/*/.apm/skills/`.
- **`vale` reports `0 files`.** Treat the pass as NOT RUN, not as clean, and fall back to full
Step 3 judgment for the dimensions it would have covered. The bundled `Kyberforge` style is
scoped by glob in `assets/vale/.vale.ini`; a file outside those globs is silently not linted.
- **`E100 Runtime error ... does not exist` (exit 2) from `vale-wrap.sh`.** An explicit relative
`--config` was passed. Pass none: the wrapper locates its own `assets/vale/.vale.ini` from its
own path, so a resolved script path plus an unresolved config path produces exactly this. Do not
read this exit code as vale being unavailable — that misreading sends the audit down the
fallback path while vale was installed and working the whole time.
- **The `vale` binary is genuinely absent** (`command not found`). Report one INFO naming it, then
fall back to full Step 3 judgment for the description, body-discipline and patterns dimensions —
the prefilter's whole coverage. Judge those by rubric rather than dropping them.
- **A path argument that does not exist is a hard error** in `vale-wrap.sh`, deliberately: bare
`vale` would fall back to reading stdin and print a clean-looking `0 errors ... in stdin`, which
the `0 files` guard above does not catch.

View File

@@ -0,0 +1,153 @@
---
source_keys:
- agentskills-home
- agentskills-spec
- agentskills-best-practices
- agentskills-optimizing-descriptions
- agentskills-using-scripts
- context7-websites-code-claude
- claude-code-plugins-docs
- claude-code-subagents-docs
- context7-github-en-copilot
- github-custom-agents-configuration
---
# Sources
<!-- agentskills.io/llms.txt was used for initial source discovery and is not listed below; it contributed no skill file content directly. -->
## agentskills-home
- **URL:** https://agentskills.io/home.md
- **Research doc:** plugins/kyberforge/docs/research/docs/agentskillsio/sources.md
- **Description:** Agent Skills overview — what it is, why it exists, progressive disclosure model, ecosystem of 35+ implementing tools
- **Contributing files:** SKILL.md, references/skill-flow.md
- **Status:** `extracted`
## agentskills-spec
- **URL:** https://agentskills.io/specification.md
- **Research doc:** plugins/kyberforge/docs/research/docs/agentskillsio/sources.md
- **Description:** Complete SKILL.md format specification — frontmatter fields, constraints, body content, optional directories, progressive disclosure levels, file references, validation
- **Contributing files:** SKILL.md, references/skill-flow.md, references/skill-body-discipline.md, references/skill-description-quality.md, references/skill-patterns.md, references/skill-file-structure.md, references/skill-formatting-and-scripts.md, references/skill-finding-criteria.md, references/skill-validation-scripts.md
- **Status:** `extracted`
## agentskills-best-practices
- **URL:** https://agentskills.io/skill-creation/best-practices.md
- **Research doc:** plugins/kyberforge/docs/research/docs/agentskillsio/sources.md
- **Description:** Best practices for skill creators — starting from real expertise, spending context wisely, calibrating control, instruction patterns (gotchas, templates, checklists, validation loops)
- **Contributing files:** SKILL.md, references/skill-flow.md, references/skill-body-discipline.md, references/skill-patterns.md, references/skill-finding-criteria.md
- **Status:** `extracted`
## agentskills-optimizing-descriptions
- **URL:** https://agentskills.io/skill-creation/optimizing-descriptions.md
- **Research doc:** plugins/kyberforge/docs/research/docs/agentskillsio/sources.md
- **Description:** How to systematically test and improve skill descriptions for triggering accuracy — eval queries, trigger rate testing, train/validation splits, optimization loop
- **Contributing files:** SKILL.md, references/skill-flow.md, references/skill-description-quality.md, references/skill-finding-criteria.md
- **Status:** `extracted`
## agentskills-evaluating-skills
- **URL:** https://agentskills.io/skill-creation/evaluating-skills.md
- **Research doc:** plugins/kyberforge/docs/research/docs/agentskillsio/sources.md
- **Description:** Eval-driven skill quality improvement — test case design, workspace structure, assertion writing, grading, benchmarking, human review, iteration loop
- **Contributing files:** (none — eval workflow not directly informing audit dimensions)
- **Status:** `extracted`
## agentskills-using-scripts
- **URL:** https://agentskills.io/skill-creation/using-scripts.md
- **Research doc:** plugins/kyberforge/docs/research/docs/agentskillsio/sources.md
- **Description:** Using scripts in skills — one-off commands, self-contained scripts with inline dependencies, designing scripts for agentic use (no interactive prompts, --help, structured output, idempotency)
- **Contributing files:** SKILL.md, references/skill-flow.md, references/skill-formatting-and-scripts.md, references/skill-finding-criteria.md, references/skill-validation-scripts.md
- **Status:** `extracted`
## agentskills-quickstart
- **URL:** https://agentskills.io/skill-creation/quickstart.md
- **Research doc:** plugins/kyberforge/docs/research/docs/agentskillsio/sources.md
- **Description:** Step-by-step guide to creating a first skill (roll-dice example), how discovery/activation/execution work in practice
- **Contributing files:** (none — creation guide not directly informing audit criteria)
- **Status:** `extracted`
## context7-websites-code-claude
- **URL:** context7:/websites/code_claude
- **Research doc:** plugins/kyberforge/docs/research/docs/claude-code-plugins/sources.md
- **Description:** Official Claude Code documentation site indexed by Context7 — plugin manifest schema, subagent definition types, marketplace JSON format, agent markdown file format
- **Contributing files:** SKILL.md, references/agent-flow.md, references/agent-finding-criteria.md, references/agent-field-inventory.md, references/agent-description-quality.md, references/agent-body-and-delegation.md, references/agent-scope-project-user.md
- **Status:** `extracted`
## claude-code-plugins-docs
- **URL:** https://code.claude.com/docs/en/plugins
- **Research doc:** plugins/kyberforge/docs/research/docs/claude-code-plugins/sources.md
- **Description:** Official Claude Code plugin authoring guide — plugin structure, manifest fields, loading methods, skill namespacing, agent activation, marketplace submission
- **Contributing files:** SKILL.md, references/agent-flow.md, references/agent-finding-criteria.md, references/agent-field-inventory.md, references/agent-body-and-delegation.md, references/agent-scope-plugin-apm.md, references/agent-validation-scripts.md
- **Status:** `extracted`
## claude-code-subagents-docs
- **URL:** https://code.claude.com/docs/en/sub-agents
- **Research doc:** plugins/kyberforge/docs/research/docs/claude-code-plugins/sources.md
- **Description:** Official Claude Code subagent reference — definition format, all frontmatter fields, scope priority, built-in agents, CLI flags, environment variables, known limitations
- **Contributing files:** SKILL.md, references/agent-flow.md, references/agent-finding-criteria.md, references/agent-field-inventory.md, references/agent-description-quality.md, references/agent-body-and-delegation.md, references/agent-scope-plugin-apm.md, references/agent-scope-project-user.md, references/agent-validation-scripts.md
- **Status:** `extracted`
## context7-github-en-copilot
- **URL:** context7:/websites/github_en_copilot
- **Research doc:** plugins/kyberforge/docs/research/docs/github-copilot-plugins/sources.md
- **Description:** Official GitHub Copilot documentation indexed by Context7; covers CLI plugins, custom agents, SDK, and marketplace
- **Contributing files:** SKILL.md, references/agent-flow.md, references/agent-finding-criteria.md, references/agent-field-inventory.md, references/agent-description-quality.md, references/agent-body-and-delegation.md, references/agent-scope-project-user.md
- **Status:** `extracted`
## github-custom-agents-configuration
- **URL:** https://docs.github.com/en/copilot/reference/custom-agents-configuration
- **Research doc:** plugins/kyberforge/docs/research/docs/github-copilot-plugins/sources.md
- **Description:** Reference for cloud and IDE custom agent definition format — frontmatter fields, tool aliases, MCP server config, secrets interpolation, scoping hierarchy
- **Contributing files:** SKILL.md, references/agent-flow.md, references/agent-finding-criteria.md, references/agent-field-inventory.md, references/agent-description-quality.md, references/agent-body-and-delegation.md, references/agent-scope-plugin-apm.md, references/agent-scope-project-user.md, references/agent-validation-scripts.md
- **Status:** `extracted`
## github-cli-plugin-reference
- **URL:** https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-plugin-reference
- **Research doc:** plugins/kyberforge/docs/research/docs/github-copilot-plugins/sources.md
- **Description:** Full CLI plugin reference — plugin.json schema, marketplace.json schema, all CLI commands and flags, install specification formats, loading precedence, env vars, LSP config
- **Contributing files:** (none)
- **Status:** `extracted`
## github-plugins-creating
- **URL:** https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/plugins-creating
- **Research doc:** plugins/kyberforge/docs/research/docs/github-copilot-plugins/sources.md
- **Description:** How-to for creating Copilot CLI plugins — plugin structure, agent and skill authoring, hooks format, MCP config, development lifecycle
- **Contributing files:** (none)
- **Status:** `extracted`
## github-plugins-finding-installing
- **URL:** https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/plugins-finding-installing
- **Research doc:** plugins/kyberforge/docs/research/docs/github-copilot-plugins/sources.md
- **Description:** User-facing guide to discovering and installing CLI plugins — marketplace browsing commands, install/update/uninstall workflow
- **Contributing files:** (none)
- **Status:** `extracted`
## github-plugins-marketplace
- **URL:** https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/plugins-marketplace
- **Research doc:** plugins/kyberforge/docs/research/docs/github-copilot-plugins/sources.md
- **Description:** How-to for creating and publishing a plugin marketplace — marketplace.json structure, hosting options, registration commands
- **Contributing files:** (none)
- **Status:** `extracted`
## github-sdk-custom-agents
- **URL:** https://docs.github.com/en/copilot/how-tos/copilot-sdk/features/custom-agents
- **Research doc:** plugins/kyberforge/docs/research/docs/github-copilot-plugins/sources.md
- **Description:** SDK custom agent API — CustomAgentConfig fields in all five languages, session config, sub-agent lifecycle events, tool scoping, permission handling
- **Contributing files:** (none)
- **Status:** `extracted`