--- source_keys: - agentskills-spec - agentskills-best-practices --- # Body Discipline Reference Upstream source: agentskills.io — skill-authoring, best-practices. House contract: ADR-0020, 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/.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 ADR-0020 gate because no such file exists on disk. 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, ADR-0020) | 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 **421-word body** dispatching to roughly 3,000 words of references across five mutually exclusive invocations. Its whole-file count is 554 words — cite 421 when calibrating a body, or the conflation this section warns against reappears in the finding itself. ## 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 before the ADR-0020 retrofit, and are not to be refreshed against `HEAD`. Read the snapshot with `git show 5e23250:plugins/git/.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. ``` ## Auditing guidance 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