docs(adr): 0029 prompts are thin user-triggered steering messages
Record the house rule for the apm prompt primitive: a single-intent, user-triggered, parameterised message that steers existing skills or agents by name and carries no procedure of its own. It also sets the prompt description contract (one plain sentence, no trigger clause). Add the glossary terms settled in the same grill to CONTEXT.md: apm primitive, Prompt, Instruction and Hook. Narrow the Skill entry's Avoid list and log the prompt ambiguity as resolved. Refs #94 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkT7RSDwDbmrM9T34b6sTi
This commit is contained in:
38
CONTEXT.md
38
CONTEXT.md
@@ -48,7 +48,31 @@ _Avoid_: agent hygiene
|
|||||||
A reusable slash command defined as a `SKILL.md` file following the
|
A reusable slash command defined as a `SKILL.md` file following the
|
||||||
[Agent Skills open standard](https://agentskills.io), authored at
|
[Agent Skills open standard](https://agentskills.io), authored at
|
||||||
`plugins/<plugin>/.apm/skills/<skill>/SKILL.md`.
|
`plugins/<plugin>/.apm/skills/<skill>/SKILL.md`.
|
||||||
_Avoid_: command, prompt, macro
|
_Avoid_: command, macro; and "prompt" for a skill — a **Prompt** is a different artifact
|
||||||
|
|
||||||
|
**Prompt**:
|
||||||
|
A single-intent, user-triggered message with parameters, authored as
|
||||||
|
`plugins/<plugin>/.apm/prompts/<name>.prompt.md` — the text a user would otherwise type repeatedly.
|
||||||
|
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 a house rule, stricter than apm, which frames a prompt as a full workflow.
|
||||||
|
_Avoid_: command (the Claude-side deployed form), workflow, macro
|
||||||
|
|
||||||
|
**Instruction**:
|
||||||
|
A scoped rule authored as `plugins/<plugin>/.apm/instructions/<name>.instructions.md`, applied when
|
||||||
|
the agent touches files matching its `applyTo` glob. Omitting `applyTo` makes it always-on in every
|
||||||
|
session of every repo that installs the package — a legitimate way for a package to ship guidance to
|
||||||
|
consumers, but a deliberate choice, never a default. A rule for this repo alone belongs in
|
||||||
|
**AGENTS.md**, not in an instruction.
|
||||||
|
_Avoid_: rule (the Claude-side deployed form under `.claude/rules/`), guideline, standard
|
||||||
|
|
||||||
|
**Hook**:
|
||||||
|
A runtime callback a harness fires inside its own tool loop, authored as one JSON file per concern
|
||||||
|
under `plugins/<plugin>/.apm/hooks/` in apm's canonical shape — nested entries, PascalCase events,
|
||||||
|
`${PLUGIN_ROOT}` script paths — which apm renders per target. Reach is narrowed in the package's
|
||||||
|
`apm.yml` `targets:`, never by filename. The last resort among apm primitives: procedure belongs in
|
||||||
|
a **Skill**, and a hook is only for "this must always happen at this event".
|
||||||
|
_Avoid_: trigger, callback script (the script is the hook's payload, not the hook)
|
||||||
|
|
||||||
**apm package**:
|
**apm package**:
|
||||||
The deployable unit apm builds and installs — one or more skills, agents, hooks, commands, and MCP
|
The deployable unit apm builds and installs — one or more skills, agents, hooks, commands, and MCP
|
||||||
@@ -58,6 +82,13 @@ _Avoid_: bundle, module, source tree; and bare "plugin" for the *installable art
|
|||||||
ADR-0024 is an apm package and not a Claude Code plugin. "Plugin" stays correct as a modifier in the
|
ADR-0024 is an apm package and not a Claude Code plugin. "Plugin" stays correct as a modifier in the
|
||||||
repo's settled compounds — **Plugin marketplace**, "plugin units", `plugins/`.
|
repo's settled compounds — **Plugin marketplace**, "plugin units", `plugins/`.
|
||||||
|
|
||||||
|
**apm primitive**:
|
||||||
|
Any content type authored under `plugins/<name>/.apm/` — skills, agents, hooks, instructions, and
|
||||||
|
prompts. Skills and agents each have their own author skill; `primitive-author` covers the other
|
||||||
|
three, so its name is narrower in practice than the term. `factory-audit` audits all five.
|
||||||
|
_Avoid_: component, asset, artifact (unqualified); bare "primitive" when only the three
|
||||||
|
non-skill, non-agent types are meant — say "hook, instruction, or prompt"
|
||||||
|
|
||||||
**Output profile**:
|
**Output profile**:
|
||||||
A named ecosystem format `apm pack` can compile the marketplace manifest into, declared per profile
|
A named ecosystem format `apm pack` can compile the marketplace manifest into, declared per profile
|
||||||
under root `apm.yml`'s `marketplace.outputs:`. apm defines `claude` and `codex`; each writes to its
|
under root `apm.yml`'s `marketplace.outputs:`. apm defines `claude` and `codex`; each writes to its
|
||||||
@@ -193,3 +224,8 @@ _Avoid_: namespace, category
|
|||||||
an audit running in the same context as the work it checks shares that work's blind spots. The
|
an audit running in the same context as the work it checks shares that work's blind spots. The
|
||||||
recheck belongs to `factory-audit`, not to `forge`, which routes only to the author
|
recheck belongs to `factory-audit`, not to `forge`, which routes only to the author
|
||||||
skills and never to an audit.
|
skills and never to an audit.
|
||||||
|
- "prompt" meant both apm's `.prompt.md` primitive and, loosely, any slash command or a skill — resolved:
|
||||||
|
a **Prompt** is the `.prompt.md` primitive under the house rule above. apm calls a prompt "a
|
||||||
|
callable program for an LLM", but on Claude it deploys as a model-invocable command with fewer
|
||||||
|
frontmatter keys than a skill, and Codex receives nothing. A fat prompt is a worse skill on every
|
||||||
|
harness, so the procedure goes in the skill and the prompt only steers it.
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# 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's docs call a prompt "a callable program for an LLM", 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 marked deprecated for Agent Host, and VS Code offers a
|
||||||
|
migration to agent skills.
|
||||||
|
- **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).
|
||||||
|
- **`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.
|
||||||
|
|
||||||
|
## 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.
|
||||||
Reference in New Issue
Block a user