|
| 1 | +--- |
| 2 | +applyTo: "internal/app/azldev/agentskill/**" |
| 3 | +description: "How to maintain azldev's emitted AI-agent skills and instruction files. Read before adding or editing a skill, an instruction wrapper, or the emit mechanism in the agentskill package." |
| 4 | +--- |
| 5 | + |
| 6 | +# Maintaining the emitted agent skills and instruction files |
| 7 | + |
| 8 | +The `agentskill` package is the **single source of truth** for the AI-agent skill and |
| 9 | +instruction files that `azldev docs agent install` writes into distro repositories, and |
| 10 | +that `azldev docs agent show` (a read-only MCP tool) serves. Everything is embedded in |
| 11 | +the binary so the on-disk files, the CLI output, and the MCP response stay version-matched. |
| 12 | + |
| 13 | +For the full architecture — the registries, the redirect-wrapper-vs-full-body rendering, |
| 14 | +and how dynamic values are substituted — read the package doc in |
| 15 | +[doc.go](../../internal/app/azldev/agentskill/doc.go). |
| 16 | + |
| 17 | +## Model |
| 18 | + |
| 19 | +- **Skills hold the content.** A `Skill` in the `skills` registry |
| 20 | + ([agentskill.go](../../internal/app/azldev/agentskill/agentskill.go)) pairs a name with a |
| 21 | + body template under [content/](../../internal/app/azldev/agentskill/content/). Skills are the |
| 22 | + cross-agent medium — served via `docs agent show` / the `docs-agent-show` MCP tool, or inlined |
| 23 | + on disk with `--full`. |
| 24 | +- **Instruction files are lightweight wrappers.** An `Instruction` in the `instructions` registry |
| 25 | + is selected by its `applyTo` glob and only *points at* skills — `SkillPointer{Skill, Purpose}` |
| 26 | + renders as "You MUST read the `<skill>` skill `<purpose>`". Put substantive guidance in a |
| 27 | + **skill**, never in a wrapper. Do not make a wrapper reference the CLI or MCP tool — those are |
| 28 | + unavailable in `--full` installs; naming the skill works in every mode. |
| 29 | + |
| 30 | +## Adding or editing a skill |
| 31 | + |
| 32 | +1. Add a `Skill{Name, Description, bodyTemplate}` to the `skills` registry. |
| 33 | +2. Add a `content/<topic>.md.tmpl` body, named for the topic (e.g. `mock.md.tmpl`, |
| 34 | + `azldev.md.tmpl`). The front-matter `name` must equal the skill's base name (and its on-disk |
| 35 | + directory), lowercase-hyphen, ≤ 64 chars. The `description` drives discovery, ≤ 1024 chars. |
| 36 | +3. Write the description inline in the registry entry. The description is the **load gate** |
| 37 | + (an agent decides whether to open the skill from it), so **lead with a directive** — |
| 38 | + "Read this before <action>; do not <do it> from memory." — then what the skill covers, |
| 39 | + then a `Triggers include ...` keyword list. |
| 40 | +4. Add a content test in |
| 41 | + [agentskill_test.go](../../internal/app/azldev/agentskill/agentskill_test.go) (assert the |
| 42 | + front-matter `name` and a distinctive, validated phrase). `TestSkillFrontmatterInvariants` |
| 43 | + auto-covers the spec limits. |
| 44 | + |
| 45 | +## Adding or editing an instruction wrapper |
| 46 | + |
| 47 | +1. Add an `Instruction{Name, ApplyTo, Description, Title, Intro, Skills}` to the `instructions` |
| 48 | + registry. `ApplyTo` may reference bindings (e.g. `{{ .RenderedSpecsDir }}/**/*`) — it is |
| 49 | + rendered against `Params` at emit time. |
| 50 | +2. `Skills` is a list of `SkillPointer` — name each skill with a short purpose ("to add or change |
| 51 | + overlays"). |
| 52 | +3. A little hand-written prose here is fine, if it helps direct agents to the right skill. Keep it short, and avoid |
| 53 | + repeating the skill content. |
| 54 | +4. Keep the count-based tests happy: `Files()` emits one file per skill plus one per instruction. |
| 55 | + |
| 56 | +## Content accuracy is the hard part |
| 57 | + |
| 58 | +Distilled content **drifts**. The azurelinux copies these are distilled from are frequently stale. |
| 59 | +Before shipping any skill/instruction: |
| 60 | + |
| 61 | +- **Validate every CLI, flag, and config claim against the current code** (command trees under |
| 62 | + `internal/app/azldev/cmds/`, config under `internal/projectconfig/`). Do not trust the source you |
| 63 | + distilled from. Confirm with `./out/bin/azldev <cmd> --help` and `azldev config generate-schema`. |
| 64 | +- Prefer a **drift-guard test** whenever a code enum can back the content. Example: |
| 65 | + `TestOverlaysSkillCoversAllOverlayTypes` extracts the overlay-type enum from the jsonschema tag |
| 66 | + on `projectconfig.ComponentOverlay.Type` and fails if the skill omits a type. |
| 67 | + |
| 68 | +## Config-resolved bindings |
| 69 | + |
| 70 | +Repo-specific values (lock dir, rendered-specs dir, work dir) are resolved from the target `azldev.toml` in |
| 71 | +[cmds/docs/agent.go](../../internal/app/azldev/cmds/docs/agent.go) and degrade to azldev's defaults |
| 72 | +when no config is present. To add a binding, extend `Bindings`, resolve it in `resolveBindings`, and |
| 73 | +reference it in a template as `{{ .FieldName }}`. |
| 74 | + |
| 75 | +## Before you commit |
| 76 | + |
| 77 | +- `mage unit` and `mage check all` pass. |
| 78 | +- `mage docs` produces **no drift** (adding a registry skill/instruction should not change CLI docs, |
| 79 | + the JSON schema, or the MCP snapshot). |
| 80 | +- Sanity-check emitted output: `./out/bin/azldev docs agent install -o "$(mktemp -d)"` and |
| 81 | + `./out/bin/azldev docs agent show --skill <name>`. |
0 commit comments