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:
2026-08-14 21:13:13 +00:00
parent 1c6eababb0
commit 4a5c3c0cff
104 changed files with 6272 additions and 1880 deletions

View File

@@ -0,0 +1,173 @@
---
source_keys:
- agentskills-home
- agentskills-spec
- agentskills-best-practices
- agentskills-quickstart
- agentskills-using-scripts
---
# Creating a new skill
Return to `SKILL.md` Step 4 once Step 6 below is done — validation, versioning and commit
verification are shared with the improve flow and are not repeated here.
## Prerequisites
Run `/grill-me` on the skill's design and research the target domain first. Share those outputs
in this conversation: grill context, research docs, examples, constraints.
Design for one coherent user intent — skills too narrow force multiple loads per task; too broad
are hard to activate precisely.
Before touching the filesystem, verify you have:
- [ ] A clear purpose — what specific task will this skill handle?
- [ ] Trigger scenarios — when should an agent activate it?
- [ ] Skill name (kebab-case) and destination path
If any are missing, stop and ask the user before proceeding.
**Requires `/skill-audit`** — used in `SKILL.md` Step 4 for final validation. Both skills ship in
the kyberforge plugin and are co-installed. If `/skill-audit` is unavailable, stop and ask the
user to install the kyberforge plugin before continuing.
## Package-intent gate
Judge whether the destination is meant to be inside an APM package before running the scaffold
script — the script cannot tell "no package here" apart from "package not scaffolded yet":
- Package intent but no `type:`-bearing `apm.yml` found at or above the destination (e.g. "add to
my apm package", or a sibling `.apm/`/`apm.yml` exists nearby) → **stop**, tell the user to run
`/apm-workflow configure` (`apm plugin init`, from inside the package directory) first, then
retry. Do not fall through to standalone mode.
- Otherwise (a `~/`-rooted destination, or no package context implied) → continue to Step 1.
## Step 1 — Scaffold
Run the copy script with the skill name and a path inside or at the target:
```bash
bash scripts/new-skill.sh <skill-name> <path>
```
The script walks up from `<path>` for a package boundary: an ancestor `apm.yml` with a top-level
`type:` field (`instructions`/`skill`/`hybrid`/`prompts`) means **package mode** — scaffolds into
`<package-root>/.apm/skills/<skill-name>/`, not under `<path>` (a subdirectory of the package
works fine as `<path>`). A `type:`-less `apm.yml` is a marketplace-only manifest, skipped. Hitting
`.git` or the filesystem root first means **standalone mode** — scaffolds directly into
`<path>/<skill-name>/`.
Examples:
```bash
# Package mode — packages/my-pkg/apm.yml already has `type: skill`
bash scripts/new-skill.sh my-tool packages/my-pkg/
# Standalone mode — no apm.yml/.git above ~/.agents/skills/
bash scripts/new-skill.sh my-tool ~/.agents/skills/
```
The script prints which mode it used and where the skill landed — read its output.
In package mode, read `references/deployment-modes.md` before adding any file references to
SKILL.md.
## Step 2 — Update `apm.yml` includes (package mode only)
Skip in standalone mode. In package mode, check the resolved package's `apm.yml`: if `includes:`
is an explicit list (not `auto`), append `.apm/skills/<skill-name>/` to it if not already present,
preserving YAML formatting. If `includes: auto` or the field is absent, do nothing — `auto`
already covers the new skill. Use Read/Edit directly on `apm.yml`; this is not part of
`scripts/new-skill.sh`.
## Step 3 — Fill in SKILL.md
Open the new skill's `SKILL.md` (the path Step 1 printed) and replace every `FILL IN:`
placeholder. The scaffold template already carries the compliant frontmatter and body skeleton —
fill it rather than restructuring it.
**`name`** — already set by the scaffold script. Must exactly match the directory name. Format:
1–64 characters, lowercase letters, numbers and hyphens only; no leading, trailing or consecutive
hyphens (`--`).
**`description`** — carries the entire triggering burden and is preloaded every session. Write it
against `references/contract.md`, which holds the three-part shape, the banned content, the
boundary-clause form and the length tiers. A hand-invoked skill (`SKILL.md` Step 2) takes one
plain sentence and `disable-model-invocation: true` instead.
**Optional frontmatter** — uncomment and fill in, or remove entirely:
- `license` — include when distributing the skill externally
- `compatibility` — include if the skill requires specific tools, runtimes, or network access
(max 500 characters)
- `metadata` — key-value map; use `author`, `version`, `category`; add `source_keys` now (Step 6)
if research sources are in context
- `allowed-tools` — space-separated pre-approved tools; reduces permission prompts (experimental —
support varies by client)
- `disable-model-invocation` — hand-invoked skills only
**`metadata.source_keys`** — if research sources are in context, list the relevant slugs as you
write the body; do not defer this to Step 6. Agents that fill in `source_keys` late tend to omit
it entirely. Example:
```yaml
metadata:
source_keys:
- my-source-slug
- another-slug
```
**Body** — write the decision procedure only, following the body rules and patterns in
`references/contract.md`. Rename the placeholder section headings to ones that fit the skill's
structure.
## Step 4 — Add scripts (if needed)
Place executable scripts in `scripts/`. Critical rule: **no interactive prompts** — agents run
non-interactive, and blocking on TTY input hangs indefinitely. Accept all input via flags, env
vars, or stdin.
If adding a script, read `references/scripts.md` first — it covers the full contract: structured
output, pinned versions, self-contained deps, idempotency, exit codes, dry-run, error messages,
and output size limits.
If no scripts are needed, delete `scripts/README.md` and the `scripts/` directory.
## Step 5 — Add references, assets, and tests (if needed)
**`references/`** — additional documentation loaded on demand. One topic per file. Reference
conditionally from SKILL.md with the literal form ``If <condition>, read `references/<file>.md` ``.
Keep reference chains one level deep — a reference file that references another reference file is
rarely loaded correctly.
**`assets/`** — static resources: templates, schemas, lookup tables. Reference by relative path
from SKILL.md.
**`tests/`** — test files for scripts in `scripts/`. Use when scripts are complex enough to break
silently. Test infrastructure (`.bats`, `*_test.*`) belongs here, not in `scripts/`. See
`tests/README.md` for setup instructions.
If not needed, delete the placeholder READMEs and their directories.
## Step 6 — Populate or delete `references/sources.md`
If a research `sources.md` is present in the conversation context:
1. Read it and filter to entries with `` `extracted` `` status only.
2. For each entry, determine which skill files it contributed to (SKILL.md and any files in
`references/` that drew from it). Update `Contributing files` accordingly — list skill files,
not research topic files.
3. Write the updated content to `references/sources.md`. For each entry, include
`- **Research doc:** <path>` where `<path>` is the relative path from the repo root to the
plugin-level research sources file this entry was drawn from (e.g.
`plugins/myplugin/docs/research/docs/<topic>/sources.md`). This field is required on every
entry — it makes the provenance chain explicit and is validated by `/skill-audit`.
4. Add `source_keys` to the frontmatter of `SKILL.md` (under `metadata`) listing the slugs of
sources that informed it.
5. For each file in `references/` that was informed by research sources, add `source_keys`
frontmatter (same format as research topic files) listing the relevant slugs.
If no research `sources.md` is in context, delete `references/sources.md`.
Then return to `SKILL.md` Step 4.