feat(kyberforge): enforce the ADR-0020 context contract for skills and agents
Skill name+description pairs are preloaded into every session, costing ~6,200 tokens across 39 skills before any skill is invoked. The authoring rules mandated that growth: skill-author:104 and description-quality.md:21 both required padding, while skill-author:102 (the deflating rule) had no FAIL condition behind it. Gates (blocking, no baseline file): - description 250 chars SUGGESTION / 400 FAIL, measured on the folded YAML value - body-only 600 words SUGGESTION / 900 FAIL, independent of the unchanged whole-file 2770-word / 500-line spec backstop - every boundary-clause routing target must resolve to a real skill or agent; catches skill-improve, neuledge-context and gitea-labels - agents take the description gates but deliberately no body gate; a test pins that absence Vale: DescriptionOpener widened to ^This\b, new CompositionNote rule banning architecture notes from descriptions. 10 hits, 0 false positives. Kyberforge's own four skills retrofitted: descriptions 3,364 -> 938 chars (-72%), bodies 8,306 -> 2,487 words (-70%), all via the apm-workflow dispatch pattern. Fixes the skill-improve dangling route and the agent-author misroute to manual review. Also fixes a pre-existing false positive where any line-initial 'read ' was flagged as interactive input, which had already caused two scripts to be rewritten around it. Refs: ADR-0020
This commit is contained in:
@@ -10,6 +10,10 @@ Additional documentation agents load on demand.
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `description-quality.md` | Qualitative guide for borderline description findings — action-verb rules, specificity criteria, proactive-use caveat, length limits. |
|
||||
| `field-inventory.md` | Canonical list of valid CC and Copilot agent definition fields. Load when the script needs authoritative field lists for structural validation. |
|
||||
| `description-quality.md` | Rubric for the description dimension — three-part shape, the 250/400-character budget, the hand-invoked contract, and the internal-mechanics FAIL. |
|
||||
| `body-and-delegation.md` | Rubric for the body, delegation and comment-discipline dimensions — the delegation FAIL, why agents take no body word gate, and what an agent body is for. |
|
||||
| `scope-plugin-apm.md` | Contract for a single vendor-neutral `.apm/agents/<name>.agent.md` file — allowlist, dimension routing, and the dimensions that do not apply. |
|
||||
| `scope-project-user.md` | Contract for a Claude Code / Copilot file pair — counterpart derivation, provider field rules, and pair consistency. |
|
||||
| `validation-scripts.md` | Loaded only when a Step 1 script fails or cannot run — scope-detection walk-up, manual fallback checks, and known script failures. |
|
||||
| `field-inventory.md` | Authoritative field lists, read as data by `validate.sh`: valid CC and Copilot agent fields, and the vendor-neutral plugin/APM allowlist. |
|
||||
| `sources.md` | Research provenance records for skill content. Load only when tracing the origin of a specific rule or field constraint. |
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
---
|
||||
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: ADR-0020, 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
|
||||
|
||||
ADR-0020 gates a skill body at 600 words SUGGESTION / 900 FAIL and deliberately gates an agent body
|
||||
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.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.
|
||||
- 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.
|
||||
|
||||
## Auditing guidance
|
||||
|
||||
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 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
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
source_keys:
|
||||
- context7-websites-code-claude
|
||||
- claude-code-plugins-docs
|
||||
- claude-code-subagents-docs
|
||||
- context7-github-en-copilot
|
||||
- github-custom-agents-configuration
|
||||
@@ -9,41 +8,120 @@ source_keys:
|
||||
|
||||
# Agent Description Quality Reference
|
||||
|
||||
Load this file when a description finding is borderline and you need to make a precise call.
|
||||
Upstream source: Claude Code subagent reference, GitHub Copilot custom-agents configuration.
|
||||
House contract: ADR-0020, 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.
|
||||
|
||||
## Action-verb opening
|
||||
## Why the description is the expensive part
|
||||
|
||||
The description must open with an imperative or present-tense verb that describes what the agent does ("Reviews...", "Audits...", "Generates...", "Analyzes..."). Avoid:
|
||||
- Noun phrases: "An agent that..." — no verb
|
||||
- "This agent..." or "Use this when..." — passive framing
|
||||
- "Helps with..." — too vague to be a clear verb
|
||||
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.
|
||||
|
||||
**Borderline call:** "Validates and reviews..." is acceptable — two verbs is fine if both are specific. "Assists in reviewing..." is not — "assists" is vague filler.
|
||||
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.
|
||||
|
||||
## Specificity of trigger condition
|
||||
## Step 0 — establish which contract applies
|
||||
|
||||
The description must state what specifically triggers the agent. Generic phrasing fails:
|
||||
- Too vague: "when the user needs help with agents"
|
||||
- Acceptable: "when the user says 'audit this agent', 'check if my agent follows best practices', or wants to know if an agent pair is ready to ship"
|
||||
Read the frontmatter before judging a single word.
|
||||
|
||||
Include indirect triggers: "even if they don't use the word 'audit'" or "even if the user doesn't phrase it as a review request". If the agent should activate on a recognisable user goal (not just literal keyword matches), name that goal.
|
||||
- **`disable-model-invocation: true` or `user-invocable: false`** — 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. Both fields are Copilot-only and neither
|
||||
is 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.
|
||||
- **No such flag** — the agent is model-invoked and the rest of this file applies.
|
||||
|
||||
**Borderline call:** If the description covers direct triggers but omits common indirect phrasings that a user would plausibly use, mark as SUGGESTION (not FAIL) — the agent still activates, just less reliably.
|
||||
## The three-part shape
|
||||
|
||||
## `Use proactively`
|
||||
A model-invoked description carries exactly three things:
|
||||
|
||||
For CC files: including "Use proactively" signals the CC runtime to offer the agent unprompted when conditions are met. This is CC-specific — use it when the agent should activate without an explicit user request.
|
||||
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.
|
||||
|
||||
For Copilot files: this phrase has no effect. Use `user-invocable: false` / `disable-model-invocation: true` for equivalent Copilot behavior. Flag `Use proactively` in a Copilot description as a SUGGESTION (not FAIL) — it causes no harm, just has no effect.
|
||||
Everything else belongs in the body or in the plugin's `README.md`.
|
||||
|
||||
## Length and hard limits
|
||||
## Indirect triggers — conditional, never blanket
|
||||
|
||||
- CC agent descriptions: no documented character limit, but keep under 500 characters to avoid truncation in UI contexts.
|
||||
- Copilot agent descriptions: no separate documented limit, but the overall 30,000-character body limit applies to the full file.
|
||||
- Skill descriptions (SKILL.md): hard 1024-character limit enforced by the platform.
|
||||
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.
|
||||
|
||||
## Do not use when
|
||||
## Near-miss exclusions
|
||||
|
||||
Include a "Do not use when..." clause only if a near-miss agent or skill exists that could steal activations. Omitting it is not a finding. Including it is correct when there is a real confusion risk (e.g., `/agent-audit` vs `/skill-audit`).
|
||||
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.
|
||||
|
||||
**Borderline call:** If the "Do not use when" clause is present but the exclusion described is already obvious from context, mark as SUGGESTION to tighten or remove — not FAIL.
|
||||
## 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.
|
||||
```
|
||||
|
||||
## Auditing guidance
|
||||
|
||||
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 — unlike a skill's 1,024-character
|
||||
spec limit, the 400-character house ceiling is the only hard limit there is, so 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`. There is no action-verb rule
|
||||
here and never was a defensible one: an `Orchestrates ...` or `Audits ...` opener is a catalogue
|
||||
entry, not a trigger.
|
||||
- **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.
|
||||
- **A boundary clause naming a target that does not resolve** to a real skill directory or agent
|
||||
file in the authoring source. No script checks this for an agent file — `validate.sh` resolves
|
||||
boundary targets for skills only, so resolve the name yourself against `plugins/*/.apm/skills/`
|
||||
and `plugins/*/.apm/agents/`.
|
||||
- **`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.
|
||||
|
||||
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.
|
||||
|
||||
@@ -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/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.
|
||||
|
||||
`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 `field-inventory.md`.
|
||||
@@ -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/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` / `user-invocable`, which changes the
|
||||
description contract entirely — see `references/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/description-quality.md`, not a pair-consistency finding.
|
||||
|
||||
Keep `pair-consistency` in the Step 4 coverage line at these scopes.
|
||||
@@ -14,7 +14,7 @@ source_keys:
|
||||
- **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/field-inventory.md, references/description-quality.md
|
||||
- **Contributing files:** SKILL.md, references/field-inventory.md, references/description-quality.md, references/body-and-delegation.md, references/scope-project-user.md
|
||||
- **Status:** `extracted`
|
||||
|
||||
## claude-code-plugins-docs
|
||||
@@ -22,7 +22,7 @@ source_keys:
|
||||
- **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/field-inventory.md, references/description-quality.md
|
||||
- **Contributing files:** SKILL.md, references/field-inventory.md, references/body-and-delegation.md, references/scope-plugin-apm.md, references/validation-scripts.md
|
||||
- **Status:** `extracted`
|
||||
|
||||
## claude-code-subagents-docs
|
||||
@@ -30,7 +30,7 @@ source_keys:
|
||||
- **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/field-inventory.md, references/description-quality.md
|
||||
- **Contributing files:** SKILL.md, references/field-inventory.md, references/description-quality.md, references/body-and-delegation.md, references/scope-plugin-apm.md, references/scope-project-user.md, references/validation-scripts.md
|
||||
- **Status:** `extracted`
|
||||
|
||||
## context7-github-en-copilot
|
||||
@@ -38,7 +38,7 @@ source_keys:
|
||||
- **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/field-inventory.md, references/description-quality.md
|
||||
- **Contributing files:** SKILL.md, references/field-inventory.md, references/description-quality.md, references/body-and-delegation.md, references/scope-project-user.md
|
||||
- **Status:** `extracted`
|
||||
|
||||
## github-custom-agents-configuration
|
||||
@@ -46,7 +46,7 @@ source_keys:
|
||||
- **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/field-inventory.md, references/description-quality.md
|
||||
- **Contributing files:** SKILL.md, references/field-inventory.md, references/description-quality.md, references/body-and-delegation.md, references/scope-plugin-apm.md, references/scope-project-user.md, references/validation-scripts.md
|
||||
- **Status:** `extracted`
|
||||
|
||||
## github-cli-plugin-reference
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
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. Silence from it is a pass, not a skip you need to
|
||||
investigate.
|
||||
|
||||
## 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/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/field-inventory.md`.
|
||||
|
||||
## Script-specific failures
|
||||
|
||||
- **`Error: field-inventory.md not found` (exit 2).** `validate.sh` reads its field lists from
|
||||
`references/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.
|
||||
Reference in New Issue
Block a user