- 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
85 lines
5.6 KiB
Markdown
85 lines
5.6 KiB
Markdown
# 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 `/deploy` and work
|
|
the same way", and both are model-invocable by default (code.claude.com/docs/en/skills.md).
|
|
apm 0.28.0 keeps only `description`, `allowed-tools`, `model`, `argument-hint` and `input` for
|
|
Claude (`_PRESERVED_COMMAND_KEYS`) and drops `disable-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 to `skill-author`.
|
|
- **`factory-audit`, script checks.**
|
|
- `description` is 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 -> Y` boundary 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-audit` gains a prompt mode.** `*.prompt.md` is a Step 0 dispatch row with its own
|
|
`references/prompt-flow.md`, and `scripts/lib-checks-primitive.sh` carries 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-author` refuses 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 to
|
|
`skill-author` before 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.
|