- cite the VS Code prompt-file deprecation and the verbatim apm quote - add ADR-0029 boundary-clause enforcement and Consequences - mark superseded ADR-0019 passages; record neutral lock advice, source fork and reloadSkills, amend for the hook hardening - move the ADR-0025 amendment out of the Decision list - amend ADR-0022 for create keeping 0.1.0 - fix hooks.md merge and event claims, README guard caveat, gates.md Vale globs, and pin the research registry URL Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkT7RSDwDbmrM9T34b6sTi
5.6 KiB
Prompts are thin, user-triggered steering messages; procedure belongs in a skill
Status: accepted (2026-09-28). Refs #94. Sets the house rule that primitive-author enforces
when it writes a .prompt.md, and that factory-audit checks in its prompt flow.
A Prompt (the term is in CONTEXT.md) is a single-intent, user-triggered message with
parameters. It is the text a user would otherwise type again and again. It carries no procedure
beyond steering existing skills or agents by name. Once it holds reusable know-how, bundled files,
or anything the model should find on its own, it is a Skill in the wrong container.
This is stricter than apm. apm frames a prompt as a program: its docs state that "a prompt is a
program for an LLM" (microsoft.github.io/apm/concepts/what-is-apm/, "Secure by default"; the same
sentence is in the apm-cli 0.28.0 package README), and 0.28.0 scaffolds one as a numbered-steps
workflow (apm_cli/workflow/discovery.py). On every harness this repo targets, a prompt with a full
workflow in it is a worse skill:
- Claude Code. Custom commands have been merged into skills. "Both create
/deployand work the same way", and both are model-invocable by default (code.claude.com/docs/en/skills.md). apm 0.28.0 keeps onlydescription,allowed-tools,model,argument-hintandinputfor Claude (_PRESERVED_COMMAND_KEYS) and dropsdisable-model-invocation. A deployed prompt is therefore a model-visible skill with fewer frontmatter keys, and it cannot be made user-only. - Copilot / VS Code. "Prompt files are deprecated for Agent Host sessions and aren't loaded by Agent Host", and VS Code offers a migration that converts existing prompt files to agent skills (code.visualstudio.com/docs/agent-customization/prompt-files). They still load in the Local agent, which that page says will be removed in a future release.
- Codex. Codex receives no prompts at all.
The one job a prompt does better than a skill is a short, parameterised "do this now, using X and Y"
message, where input: → $arguments is the whole point.
Description contract
A prompt's description is one plain, human-facing sentence that names the skills or agents it
steers. For example: "Review the current PR with gitea-prs and factory-audit, then summarise."
It has no "Use when…" trigger clause and no Not X -> Y boundary clause. This is the same shape
factory-audit already applies to disable-model-invocation: true skills. Without a trigger clause,
the router has little reason to pick the prompt over the skills it wraps. So when the model routes,
it tends to reach the real capability.
Unverified: how strongly Claude avoids routing to a description with no trigger clause. The contract lowers the chance of the model invoking the prompt, but does not prevent it. If it does happen, the cost is bounded: the prompt is a thin wrapper that calls the right skills anyway.
Enforcement
primitive-author. The prompt reference opens with a boundary gate. A request that carries procedure is redirected toskill-author.factory-audit, script checks.descriptionis present and non-empty (FAIL).- It is 250 characters or fewer (SUGGESTION).
- It has no "Use when" trigger clause (SUGGESTION).
- It has no
Not X -> Yboundary clause (SUGGESTION).
factory-audit, judgment step. A body that clearly carries reusable procedure is a FAIL. A borderline body is a SUGGESTION. There is deliberately no line-count or heading heuristic: the call is made by reading the content, because any threshold misfires.
Consequences
factory-auditgains a prompt mode.*.prompt.mdis a Step 0 dispatch row with its ownreferences/prompt-flow.md, andscripts/lib-checks-primitive.shcarries the three description checks above plus the judgment step (ADR-0025, amendment 2026-09-28). A prompt that was fine under apm's framing — a trigger clause, a boundary clause, a numbered workflow — now draws findings.primitive-authorrefuses procedure-bearing prompts. Its prompt reference opens with the boundary gate, so a "make me a command" request that carries reusable know-how is redirected toskill-authorbefore any file is written. That makes skill-vs-prompt a checked boundary rather than an authoring preference.- Codex gets no prompts from this repo. apm deploys none to Codex, so anything a prompt steers must also be reachable there through the skill it names. Keeping procedure in the skill is what makes that true; a fat prompt would be content Codex users silently never see.
- Reversing this is cheap in files, not in routing. No prompt exists in the repo yet, so the rule constrains new work only. Loosening it later means re-deciding the description contract, and every prompt written under it would need a trigger clause added.
Considered options
- Fat workflow prompts as peers of skills (rejected). This follows apm's framing. But every "make me a command" request becomes a coin flip between two near-identical containers. The prompt also carries worse metadata on Claude and does not arrive on Codex.
- The full ADR-0020 description contract for prompts (rejected). A trigger clause and a boundary clause would make prompts route well. That actively invites the model to invoke the prompt, which contradicts "user-triggered".
- Skill-by-default with prompts as a grudging exception (superseded during the grill). This framed a prompt as a weaker skill competing for the same job. Giving it a distinct role, a thin caller over skills, is a boundary that can be checked, which "prefer skills" is not.