CANP-WP-0004. The operator asked canned-prompts to build a database of versioned prompts recording where each came from and when — the first step toward a platform for collaborative prompting. The format had nowhere to put that. `provenance` records who wrote a prompt and where the idea came from; nothing recorded how a copy arrived in a particular store. Section 20.3 now specifies an `index.yaml` as store metadata rather than package data: how a copy arrived differs for every consumer, and recording an arrival must never rewrite the package that arrived. `add`, `install` and `publish` record registry, id, version, name, source, method, first-inclusion date, and the package's declared author, source and licence — the last three copied so a listing is readable without opening every package. A new `index` verb lists it. `included_at` is never overwritten; a re-run updates `last_seen_at`, because when a package first entered a collection is a fact about history rather than about the last command run. Tests 84 -> 90. Also records two findings from actually using the format: CANP-WP-0004-T03 — inclusion has no deduplication, so a diamond dependency renders shared content once per path. Found by composing a real collection. Not fixed here: deduplicating means choosing which occurrence survives and deciding what happens when two paths resolve different versions, which is resolver behaviour that section 10.4 deliberately avoids. Handed to CANP-WP-0005 with a leaning: document it, warn at validation time, do not deduplicate. The add_ons workaround in practice/pqrst-estimate is evidence about section 23's deferred "richer template syntax" — an optional appendix has to be an input with an empty default, because CPF has no conditionals. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bjefh8NUiEiahN4JLwoSKM Assistant: claude-code Assistant-Model: opus Assistant-Process: 388925@bnt-lap001 Assistant-Session: 3507023f-e0fd-4a1e-9d90-a0d4217d1502
1305 lines
43 KiB
Markdown
1305 lines
43 KiB
Markdown
# Canned Prompt Format
|
|
|
|
**Revision:** v0.2 — packages declare `format: canned-prompt/v0.2`
|
|
**Status:** Experimental
|
|
**Project:** `canned-prompts`
|
|
**Purpose:** Portable packaging of reusable prompts and prompt templates.
|
|
**Compatibility:** packages declaring `canned-prompt/v0.1` remain valid (§ 3.2).
|
|
|
|
## 1. Goals
|
|
|
|
The Canned Prompt Format (CPF) defines the smallest practical contract for a reusable prompt artifact.
|
|
|
|
A conforming package should be:
|
|
|
|
- human-readable;
|
|
- filesystem-portable;
|
|
- provider-neutral;
|
|
- inspectable before use;
|
|
- parameterizable where useful;
|
|
- versionable;
|
|
- extensible with examples, evals, dependencies, and provenance.
|
|
|
|
CPF specifies the **artifact format**. It intentionally does not specify model execution, agent orchestration, dependency resolution, registry transport, or evaluation engines.
|
|
|
|
## 2. Package layout
|
|
|
|
The minimum valid package is:
|
|
|
|
```text
|
|
my-prompt/
|
|
├── prompt.yaml
|
|
└── prompt.md
|
|
```
|
|
|
|
A richer package may contain:
|
|
|
|
```text
|
|
my-prompt/
|
|
├── prompt.yaml
|
|
├── prompt.md
|
|
├── README.md
|
|
├── examples/
|
|
│ ├── basic.yaml
|
|
│ └── edge-case.yaml
|
|
├── evals/
|
|
│ └── quality.yaml
|
|
└── assets/
|
|
└── rubric.md
|
|
```
|
|
|
|
### Reserved paths
|
|
|
|
| Path | Meaning |
|
|
|---|---|
|
|
| `prompt.yaml` | Required package manifest |
|
|
| `prompt.md` | Default prompt template unless overridden by `template` |
|
|
| `README.md` | Optional human documentation |
|
|
| `LICENSE` | Optional license text |
|
|
| `examples/` | Optional examples/fixtures |
|
|
| `evals/` | Optional evaluation specifications |
|
|
| `assets/` | Optional supporting text/data artifacts |
|
|
|
|
Tools MUST ignore unknown non-reserved files unless a manifest field explicitly references them.
|
|
|
|
This governs packaging as well as reading: a tool that copies a package into a
|
|
catalog or registry MUST copy the reserved paths and the files a manifest
|
|
field references, and nothing else. A working directory's `.git`, virtualenv or
|
|
scratch files are not part of the package and MUST NOT be published with it. A
|
|
tool that omits files SHOULD say which, so that an author is never silently
|
|
surprised by what did not ship.
|
|
|
|
`LICENSE` is reserved because § 14 asks tools to surface licensing on publish
|
|
and install, and because dropping the license text while faithfully copying the
|
|
`license` field would misrepresent the package.
|
|
|
|
## 3. Manifest
|
|
|
|
The canonical manifest is UTF-8 YAML named `prompt.yaml`.
|
|
|
|
### 3.1 Minimal manifest
|
|
|
|
```yaml
|
|
format: canned-prompt/v0.2
|
|
id: review/code-review
|
|
name: Code Review
|
|
version: 1.0.0
|
|
summary: Review a change for correctness and maintainability.
|
|
template: prompt.md
|
|
```
|
|
|
|
Required fields are:
|
|
|
|
- `format`
|
|
- `id`
|
|
- `name`
|
|
- `version`
|
|
- `summary`
|
|
- `template`
|
|
|
|
### 3.2 Package identity
|
|
|
|
#### `format`
|
|
|
|
The current revision is:
|
|
|
|
```yaml
|
|
format: canned-prompt/v0.2
|
|
```
|
|
|
|
A package declaring `canned-prompt/v0.1` remains valid and MUST still be
|
|
accepted. Everything v0.2 adds is additive — input defaults, composition, the
|
|
eval schema, registry manifests — so a v0.1 package means exactly what it
|
|
always meant. By § 17's own guidance this is a MINOR revision: new capability,
|
|
unchanged contract.
|
|
|
|
A consumer MUST reject a `format` it does not recognize rather than guessing at
|
|
its meaning.
|
|
|
|
#### `id`
|
|
|
|
A stable, registry-independent logical identifier.
|
|
|
|
Recommended syntax:
|
|
|
|
```text
|
|
<namespace>/<name>
|
|
```
|
|
|
|
Examples:
|
|
|
|
```text
|
|
review/code-review
|
|
engineering/architecture-review
|
|
practice/pqrst-estimate
|
|
```
|
|
|
|
Rules:
|
|
|
|
- lowercase ASCII is RECOMMENDED;
|
|
- `/`, `-`, `_`, and `.` MAY be used;
|
|
- whitespace MUST NOT be used;
|
|
- the ID MUST NOT contain `..` path traversal segments;
|
|
- `:` MUST NOT be used, so that it remains available as the registry separator
|
|
in a qualified reference (below);
|
|
- registry implementations MUST treat the ID as logical metadata rather than an unchecked filesystem path.
|
|
|
|
##### Identity is registry-scoped
|
|
|
|
An `id` names a package **within a registry**, the way a path names a file
|
|
within a repository. CPF does **not** claim that an id is globally unique:
|
|
`practice/pqrst-estimate` obtained from two different registries may be two
|
|
different packages, and a consumer that draws on more than one registry MUST
|
|
keep track of which registry each package came from.
|
|
|
|
This follows from what the format actually guarantees. A local-first format
|
|
with no signing, no federation and no central authority (all explicit
|
|
non-goals) cannot enforce global uniqueness, and a guarantee that cannot be
|
|
enforced is worse than none — it invites consumers to conflate two packages
|
|
that merely share a name.
|
|
|
|
Where a consumer must distinguish them, a **qualified reference** names the
|
|
registry:
|
|
|
|
```text
|
|
<registry>:<id>
|
|
```
|
|
|
|
For example:
|
|
|
|
```text
|
|
house:practice/pqrst-estimate
|
|
upstream:practice/pqrst-estimate
|
|
```
|
|
|
|
An unqualified id is acceptable wherever it is unambiguous for that consumer.
|
|
A tool that finds the same id in more than one registry MUST report the
|
|
ambiguity rather than choosing for the caller.
|
|
|
|
#### `name`
|
|
|
|
Human-readable display name.
|
|
|
|
#### `version`
|
|
|
|
A package version. Semantic Versioning (`MAJOR.MINOR.PATCH`) is RECOMMENDED and used by the reference implementation.
|
|
|
|
Behavior-changing edits SHOULD create a new version rather than overwrite a published package.
|
|
|
|
#### `summary`
|
|
|
|
A short description of the intended purpose. A consumer SHOULD be able to decide whether a package is potentially relevant from `name` + `summary` alone.
|
|
|
|
#### `template`
|
|
|
|
Relative path to the primary prompt template inside the package. The path MUST remain within the package directory.
|
|
|
|
#### `type`
|
|
|
|
Declares what kind of artifact the package is. Optional; defaults to
|
|
`template`.
|
|
|
|
| Value | Meaning |
|
|
|---|---|
|
|
| `template` | A complete prompt, intended to be used on its own |
|
|
| `fragment` | A reusable block intended for inclusion in other packages (§ 10.4) |
|
|
|
|
`type` is advisory. A fragment is a perfectly valid package and MAY be
|
|
rendered on its own; the field records the author's intent so that a consumer
|
|
can warn when a package is used against it — rendering a fragment as a
|
|
standalone prompt, or including a whole template where a fragment was meant.
|
|
|
|
## 4. Complete manifest surface
|
|
|
|
```yaml
|
|
format: canned-prompt/v0.2
|
|
id: review/code-review
|
|
name: Code Review
|
|
version: 1.2.0
|
|
summary: >
|
|
Review a change for correctness, maintainability,
|
|
security and test coverage.
|
|
|
|
type: template
|
|
template: prompt.md
|
|
|
|
inputs:
|
|
- name: change
|
|
type: content
|
|
required: true
|
|
description: The code, diff, or change to review.
|
|
|
|
- name: repository_context
|
|
type: content
|
|
required: false
|
|
description: Optional surrounding repository context.
|
|
default:
|
|
derive: context/repository-summary
|
|
value: "(no repository context provided)"
|
|
|
|
parameters:
|
|
depth:
|
|
type: enum
|
|
values: [quick, normal, thorough]
|
|
default: normal
|
|
description: Desired review depth.
|
|
|
|
include_security:
|
|
type: boolean
|
|
default: true
|
|
|
|
output:
|
|
format: markdown
|
|
description: A structured review with findings and recommendations.
|
|
|
|
compatibility:
|
|
capabilities:
|
|
- long-context
|
|
models: []
|
|
providers: []
|
|
|
|
dependencies:
|
|
prompts:
|
|
- id: context/repository-summary
|
|
version: 1.0.0
|
|
requirement: generate
|
|
context:
|
|
- name: repository-tree
|
|
description: A listing of the repository under review.
|
|
requirement: optional
|
|
capabilities:
|
|
- code-analysis
|
|
|
|
examples:
|
|
- examples/basic.yaml
|
|
|
|
evals:
|
|
- evals/review-quality.yaml
|
|
|
|
license: CC-BY-4.0
|
|
|
|
tags:
|
|
- code-review
|
|
- engineering
|
|
|
|
provenance:
|
|
author: Example Author
|
|
source: https://example.invalid/original
|
|
derived_from: []
|
|
|
|
extensions: {}
|
|
```
|
|
|
|
All fields other than the required fields in section 3.1 are optional.
|
|
|
|
## 5. Prompt template syntax
|
|
|
|
CPF uses deliberately small placeholder semantics:
|
|
|
|
```text
|
|
{{ variable_name }}
|
|
```
|
|
|
|
A placeholder name MUST correspond to either:
|
|
|
|
- a declared `input`, or
|
|
- a declared `parameter`.
|
|
|
|
Whitespace immediately inside `{{` and `}}` is insignificant.
|
|
|
|
Examples:
|
|
|
|
```markdown
|
|
Review the following change at {{ depth }} depth.
|
|
|
|
{{ change }}
|
|
```
|
|
|
|
### 5.1 Resolution and rendering
|
|
|
|
Producing a final prompt is two steps:
|
|
|
|
1. **Resolve** — determine a value for every declared input and parameter.
|
|
2. **Render** — substitute those values into the template as text.
|
|
|
|
The steps are separate because only the first may be non-deterministic.
|
|
**Rendering is deterministic:** the same resolved values and the same template
|
|
always produce the same output. A consumer that satisfies a derived default
|
|
(§ 6.1) does so during resolution, never during rendering.
|
|
|
|
**Resolution rules:**
|
|
|
|
1. Call-supplied values override defaults.
|
|
2. A declared parameter default is used when no call value is supplied.
|
|
3. A declared static input default is used when no call value is supplied.
|
|
4. A required input without a value is an error.
|
|
5. A derived input default is satisfied only by a consumer that is able and
|
|
permitted to derive it. A consumer that does not derive uses the default's
|
|
static fallback `value` when one is declared, and otherwise leaves the
|
|
input unresolved.
|
|
6. An included input default is satisfied by rendering the included package
|
|
(§ 10.4). This is deterministic, so a consumer that can render can satisfy
|
|
it; one that cannot locate the package uses the static fallback `value`
|
|
when declared, and otherwise leaves the input unresolved.
|
|
7. Resolution MUST report which values were derived or included, so that a
|
|
caller can see what was added on its behalf before the prompt is used.
|
|
|
|
**Rendering rules:**
|
|
|
|
8. Values are substituted as text.
|
|
9. A placeholder with no resolved value is an error.
|
|
10. Template evaluation MUST NOT execute arbitrary code.
|
|
11. Rendering MUST NOT derive values. A tool offering derivation MUST perform
|
|
it as a distinct resolve step whose results are visible to the caller
|
|
before rendering. Inclusion likewise happens during resolution; rendering
|
|
only substitutes.
|
|
|
|
A minimal implementation may implement resolution for supplied values and
|
|
static defaults only. Such a tool is conforming: it reports an input with an
|
|
unsatisfied derived default and no static fallback as unresolved, which
|
|
rule 9 makes an error.
|
|
|
|
CPF does not define conditionals, loops, filters, or functions. Implementations MAY offer richer rendering modes only when explicitly declared by an extension; they MUST NOT silently reinterpret a template as executable code.
|
|
|
|
## 6. Inputs
|
|
|
|
`inputs` is an optional ordered list.
|
|
|
|
```yaml
|
|
inputs:
|
|
- name: document
|
|
type: content
|
|
required: true
|
|
description: Document to summarize.
|
|
```
|
|
|
|
Fields:
|
|
|
|
| Field | Required | Meaning |
|
|
|---|---:|---|
|
|
| `name` | yes | Placeholder/input identifier |
|
|
| `type` | no | Suggested semantic type; defaults to `content` |
|
|
| `required` | no | Whether a caller must supply it; defaults to `false` |
|
|
| `description` | no | Human-readable explanation |
|
|
| `default` | no | Value used when the caller supplies none; see § 6.1 |
|
|
|
|
Recommended input types are:
|
|
|
|
- `content`
|
|
- `text`
|
|
- `url`
|
|
- `path`
|
|
- `json`
|
|
|
|
These are descriptive hints. A runtime MAY use them for validation or adapters.
|
|
|
|
### 6.1 Input defaults
|
|
|
|
An input MAY declare a `default`, used when the caller supplies no value.
|
|
|
|
`default` MUST NOT be combined with `required: true`: a required input is always
|
|
supplied by the caller, so a default could never apply.
|
|
|
|
Without this field an optional input is close to unusable. Rendering rule 8
|
|
makes an unresolved placeholder an error, so an input marked `required: false`
|
|
and referenced from the template would fail every render in which the caller
|
|
omitted it.
|
|
|
|
A default takes one of two forms.
|
|
|
|
#### Static default
|
|
|
|
A literal value, used as-is:
|
|
|
|
```yaml
|
|
inputs:
|
|
- name: repository_context
|
|
type: content
|
|
required: false
|
|
default: "(no repository context provided)"
|
|
```
|
|
|
|
Every conforming implementation supports static defaults.
|
|
|
|
#### Derived default
|
|
|
|
A declaration that the value **may** be produced from available context by a
|
|
consumer able to do so. It is a request to the consumer, not an instruction the
|
|
package executes.
|
|
|
|
The preferred form references a package already declared in
|
|
`dependencies.prompts` with `requirement: generate` (§ 10):
|
|
|
|
```yaml
|
|
dependencies:
|
|
prompts:
|
|
- id: context/repository-summary
|
|
version: 1.0.0
|
|
requirement: generate
|
|
|
|
inputs:
|
|
- name: repository_context
|
|
type: content
|
|
required: false
|
|
default:
|
|
derive: context/repository-summary
|
|
value: "(no repository context provided)"
|
|
```
|
|
|
|
A derivation prompt MAY instead be written inline:
|
|
|
|
```yaml
|
|
inputs:
|
|
- name: repository_context
|
|
type: content
|
|
required: false
|
|
default:
|
|
derive:
|
|
prompt: |
|
|
Summarize the repository this prompt is being run against,
|
|
in under 200 words.
|
|
value: "(no repository context provided)"
|
|
```
|
|
|
|
`derive` is therefore either a string naming a declared prompt dependency, or a
|
|
mapping carrying an inline `prompt`. A single default MUST NOT use both.
|
|
|
|
Prefer the reference form wherever the derivation is worth keeping. An inline
|
|
prompt is anonymous: it has no version, provenance, examples or evals, and
|
|
cannot be reused, evaluated or improved independently of its host package —
|
|
the situation this format exists to replace. Validators SHOULD warn when a
|
|
**published** package derives inline. Inline derivation is intended for local
|
|
and draft packages.
|
|
|
|
#### Included default
|
|
|
|
A default may instead **include** another package's rendered template as text
|
|
(§ 10.4). Unlike a derived default this is deterministic and needs no model,
|
|
so every implementation that can render can also include:
|
|
|
|
```yaml
|
|
dependencies:
|
|
prompts:
|
|
- id: style/house
|
|
version: 1.0.0
|
|
requirement: required
|
|
|
|
inputs:
|
|
- name: house_style
|
|
type: content
|
|
required: false
|
|
default:
|
|
include: style/house
|
|
```
|
|
|
|
`include` names a package declared in `dependencies.prompts`, exactly as a
|
|
`derive` reference does. A single default MUST declare at most one of
|
|
`include` or `derive`.
|
|
|
|
An included default MAY also declare a static fallback `value`, used by a
|
|
consumer that cannot locate the included package.
|
|
|
|
#### Static fallback
|
|
|
|
`value` inside a derived or included default is an optional **static fallback**. Its
|
|
meaning is defined by resolution rule 5: a consumer that does not derive uses
|
|
it, and an input with neither a derived value nor a fallback stays unresolved,
|
|
which rule 8 makes an error. Derivation never silently yields empty content.
|
|
The same holds for an inclusion that cannot be resolved.
|
|
|
|
Declaring a derived default does not oblige any consumer to derive anything,
|
|
and does not make the package depend on a particular resolver, model or
|
|
runtime. Resolution belongs to the consumer; the package only declares what it
|
|
would like resolved.
|
|
|
|
## 7. Parameters
|
|
|
|
`parameters` is an optional mapping keyed by parameter name.
|
|
|
|
Supported descriptive parameter types:
|
|
|
|
- `string`
|
|
- `integer`
|
|
- `number`
|
|
- `boolean`
|
|
- `enum`
|
|
|
|
Example:
|
|
|
|
```yaml
|
|
parameters:
|
|
tone:
|
|
type: enum
|
|
values: [neutral, friendly, formal]
|
|
default: neutral
|
|
|
|
max_items:
|
|
type: integer
|
|
default: 10
|
|
```
|
|
|
|
A tool SHOULD validate enum values. Other type validation is RECOMMENDED but not mandatory for a minimal implementation.
|
|
|
|
## 8. Output contract
|
|
|
|
`output` describes the intended result, not an execution protocol.
|
|
|
|
```yaml
|
|
output:
|
|
format: markdown
|
|
description: Concise structured findings.
|
|
```
|
|
|
|
Suggested `format` values include:
|
|
|
|
- `text`
|
|
- `markdown`
|
|
- `json`
|
|
- `yaml`
|
|
- `xml`
|
|
- `code`
|
|
|
|
Registries MAY index output format for discovery.
|
|
|
|
## 9. Compatibility
|
|
|
|
`compatibility` records **observations**, never requirements.
|
|
|
|
Everything here describes where the package has been seen to work. Nothing here
|
|
is a precondition for using it, and a consumer MUST NOT refuse to run a package
|
|
because its environment is absent from these lists.
|
|
|
|
```yaml
|
|
compatibility:
|
|
capabilities:
|
|
- long-context
|
|
aliases:
|
|
web-search: [browsing, tool-search]
|
|
models:
|
|
- example/model-family
|
|
providers: []
|
|
```
|
|
|
|
Semantics:
|
|
|
|
- `capabilities`: capabilities the package is known to work well with, whether
|
|
or not it requires them;
|
|
- `aliases`: the same capability as known by other names, so that a consumer
|
|
can recognize a requirement its environment labels differently;
|
|
- `models`: model identifiers known to be compatible or evaluated;
|
|
- `providers`: provider identifiers when provider-specific behavior matters.
|
|
|
|
An empty list means "not constrained/unspecified", not "compatible with nothing".
|
|
|
|
### 9.1 Required versus compatible
|
|
|
|
Earlier drafts described `compatibility` as recording "requirements or
|
|
observations" and `dependencies` as recording what a prompt "expects", so both
|
|
appeared to say the same thing about capabilities. They do not, and the
|
|
distinction is worth stating in one word each:
|
|
|
|
| Field | Meaning | Absence means |
|
|
|---|---|---|
|
|
| `dependencies` | **required** — the package does not work without it | a consumer SHOULD warn or refuse before running |
|
|
| `compatibility` | **observed** — the package is known to work with it | nothing; it is information, not a gate |
|
|
|
|
A capability the prompt cannot function without belongs in
|
|
`dependencies.capabilities`. A capability it merely benefits from, or has been
|
|
evaluated against, belongs in `compatibility.capabilities`. The same name may
|
|
legitimately appear in both: required to run at all, and separately observed to
|
|
work well on particular models.
|
|
|
|
## 10. Dependencies
|
|
|
|
Dependencies describe what a package **requires** in order to work (§ 9.1).
|
|
There are three kinds, separated by what CPF can do about them:
|
|
|
|
| Kind | Names | CPF can resolve it |
|
|
|---|---|---|
|
|
| `prompts` | other CPF packages | yes — by id and version (§ 10.3) |
|
|
| `context` | things CPF does not package | no — the consumer supplies them |
|
|
| `capabilities` | what the environment must be able to do | no — the environment either can or cannot |
|
|
|
|
```yaml
|
|
dependencies:
|
|
prompts:
|
|
- id: context/repository-summary
|
|
version: 1.0.0
|
|
requirement: optional
|
|
|
|
context:
|
|
- name: repository-tree
|
|
kind: information-space
|
|
description: A listing of the repository under review.
|
|
requirement: required
|
|
|
|
capabilities:
|
|
- web-search
|
|
```
|
|
|
|
### 10.1 Context dependencies
|
|
|
|
`context` names something the package needs that CPF neither packages nor
|
|
resolves: a live information space, an API, a corpus, a document the caller
|
|
supplies. Anything CPF *can* package is a package — a reusable policy or style
|
|
block belongs in `prompts` as a `type: fragment` package (§ 3.2), not here.
|
|
|
|
Entries use `name` rather than `id`, precisely because they are not package
|
|
identifiers and nothing can look them up.
|
|
|
|
| Field | Required | Meaning |
|
|
|---|---:|---|
|
|
| `name` | yes | What the context is called, in kebab-case |
|
|
| `description` | yes | What it is and what it must contain |
|
|
| `kind` | no | Free-form hint, e.g. `information-space`, `api`, `document`, `corpus` |
|
|
| `requirement` | no | `required` or `optional`; defaults to `required` |
|
|
|
|
`description` is required because nothing else can explain an unpackaged
|
|
dependency. A consumer meeting this entry has only the text to go on, and
|
|
INTENT principle 3 puts hidden context at odds with reuse.
|
|
|
|
A context dependency is not an input. An input is content the caller passes for
|
|
one use (§ 6); a context dependency is a standing fact about the environment
|
|
the package needs to be run in.
|
|
|
|
### 10.2 Capability dependencies
|
|
|
|
`capabilities` lists what the execution environment must be able to do, as
|
|
free-form lowercase kebab-case names — validated for shape, not for membership
|
|
in any vocabulary, exactly as `tags` are (§ 15). Standardizing model capability
|
|
vocabularies remains deferred; no real usage has yet asked for one.
|
|
|
|
A capability is not an artifact: it cannot be fetched, pinned or generated, so
|
|
it takes no version and no `requirement: generate`. It is either present or it
|
|
is not. A consumer that knows it lacks a required capability SHOULD say so
|
|
before running rather than after.
|
|
|
|
Where an environment knows the same capability by another name,
|
|
`compatibility.aliases` (§ 9) can record the correspondence.
|
|
|
|
Recommended requirement values:
|
|
|
|
- `required`
|
|
- `optional`
|
|
- `generate`
|
|
|
|
`generate` means that a resolver MAY satisfy a missing dependency by invoking an appropriate generation process. **CPF does not define how generation or dependency resolution works.**
|
|
|
|
### 10.3 Naming and pinning a dependency
|
|
|
|
A dependency's `id` MAY be a qualified `<registry>:<id>` reference (§ 3.2).
|
|
An unqualified id is resolved by the consumer against whatever registries it
|
|
draws on, and an id matching packages from more than one registry MUST be
|
|
reported as ambiguous rather than chosen.
|
|
|
|
`version` selects which version satisfies the dependency:
|
|
|
|
| `version` | Selects |
|
|
|---|---|
|
|
| a semver literal, e.g. `1.2.0` | exactly that version |
|
|
| `any` | any available version; a consumer SHOULD prefer one it already holds |
|
|
| `newest` | the newest available version |
|
|
| `>= 1.2.0` | the newest available version that is at least `1.2.0` |
|
|
|
|
Prereleases are excluded from `any`, `newest` and `>=` (§ 17.1); name one
|
|
exactly to select it.
|
|
|
|
**An exact pin is the expected form.** The other three are explicit opt-ins,
|
|
visible in the manifest, so that looseness is always something an author wrote
|
|
rather than something absence implied.
|
|
|
|
`version` is REQUIRED for any dependency referenced by a composition or a
|
|
derived default (§ 6.1), and RECOMMENDED otherwise.
|
|
|
|
This is deliberately **not** semantic version range resolution, which remains
|
|
a non-goal. There are no unions, no caret or tilde operators, and above all no
|
|
solver: each dependency is selected independently against what is available,
|
|
and no consumer is expected to satisfy constraints across a dependency graph.
|
|
A single lower bound is a selector, not a constraint system.
|
|
|
|
### 10.4 Composition
|
|
|
|
A package composes another in one of two ways, both expressed as an input
|
|
default (§ 6.1) so that composition reuses the resolution machinery rather
|
|
than adding a second one:
|
|
|
|
| Form | Produces | Deterministic |
|
|
|---|---|---|
|
|
| `include` | the other package's **rendered template**, inlined as text | yes |
|
|
| `derive` | the other package's **result**, obtained by running it | no |
|
|
|
|
`include` is text composition: a shared preamble, rubric or house-style block
|
|
becomes a real versioned package instead of copied text, and inlining it needs
|
|
no model. `derive` is output composition: the value is whatever running the
|
|
other package produces, and only a consumer able to run it can supply one.
|
|
|
|
When rendering an included package, its placeholders are resolved from the
|
|
including package's already-resolved values by name, falling back to the
|
|
included package's own defaults. An included package with a required input
|
|
that the including package does not supply is an error naming both packages.
|
|
|
|
Implementations MUST detect inclusion cycles and report them rather than
|
|
recursing.
|
|
|
|
CPF does **not** define template inheritance. A package does not extend
|
|
another, override its sections, or inherit its inputs. Composition is by
|
|
reference only, for four reasons drawn from this specification and from
|
|
`INTENT.md`: hidden context defeats reuse (INTENT principle 3); § 19 asks that
|
|
package contents be visible before execution, which an inheritance chain
|
|
prevents; § 17 asks that behavior changes produce a new version, which an
|
|
inherited change would bypass; and resolving an override chain is the kind of
|
|
graph problem the non-goals exclude.
|
|
|
|
This allows richer systems to integrate prompt resolution without forcing simple tools to implement an agent runtime.
|
|
|
|
A prompt dependency declared `requirement: generate` is the mechanism behind a
|
|
referenced derived default (§ 6.1): the input's `default.derive` names the
|
|
dependency, and a consumer able to generate satisfies both at once. Declaring
|
|
the dependency records *what* may be generated and at which version; the input
|
|
default records *where the result lands*. Neither states how generation works.
|
|
|
|
## 11. Examples
|
|
|
|
`examples` is a list of relative paths.
|
|
|
|
An example file is not normative but SHOULD make intended usage obvious.
|
|
|
|
Suggested YAML shape:
|
|
|
|
```yaml
|
|
name: basic review
|
|
values:
|
|
change: |
|
|
def add(a, b):
|
|
return a + b
|
|
depth: quick
|
|
```
|
|
|
|
Tools MAY render examples directly.
|
|
|
|
## 12. Evals
|
|
|
|
`evals` is a list of relative paths to evaluation specifications.
|
|
|
|
CPF does not standardize a universal evaluation language, which remains a
|
|
non-goal. Every eval file MUST declare a `schema`, and a consumer MUST ignore a
|
|
schema it does not recognize rather than guessing at its meaning.
|
|
|
|
CPF defines exactly one schema, so that `evals/` holds something tools can act
|
|
on rather than opaque blobs. Other schemas remain legal and are simply not
|
|
interpreted here.
|
|
|
|
### 12.1 `canned-prompts/eval-rubric/v0.1`
|
|
|
|
```yaml
|
|
schema: canned-prompts/eval-rubric/v0.1
|
|
name: pqrst-estimate-quality
|
|
description: The estimate reads as a post-session audit, not a plan.
|
|
example: examples/basic.yaml
|
|
|
|
render:
|
|
- contains: "must sum to exactly 100%"
|
|
- not_contains: "{{"
|
|
- resolves_all: true
|
|
|
|
output:
|
|
criteria:
|
|
- Percentages sum to exactly 100%.
|
|
- Categories are not silently renamed or merged.
|
|
- Rationale cites evidence from the session summary.
|
|
```
|
|
|
|
| Field | Required | Meaning |
|
|
|---|---:|---|
|
|
| `schema` | yes | MUST be `canned-prompts/eval-rubric/v0.1` |
|
|
| `name` | yes | Identifies this eval within the package |
|
|
| `description` | no | What the eval is for |
|
|
| `example` | no | Fixture to run against; MUST be a path declared in the manifest's `examples` |
|
|
| `render` | no | Deterministic checks on the **rendered prompt** |
|
|
| `output` | no | Model-judged criteria for the **result** |
|
|
|
|
An eval declaring neither `render` nor `output` asserts nothing and SHOULD be
|
|
rejected.
|
|
|
|
#### Render checks
|
|
|
|
Render checks assert properties of the rendered prompt text. They need no
|
|
model, so **any implementation that can render can run them.**
|
|
|
|
| Check | Passes when |
|
|
|---|---|
|
|
| `contains: <text>` | the rendered prompt contains that text |
|
|
| `not_contains: <text>` | it does not |
|
|
| `resolves_all: true` | every placeholder resolved to a value |
|
|
|
|
Each entry is a single-key mapping, so a check may appear more than once.
|
|
|
|
#### Output criteria
|
|
|
|
`output.criteria` is a list of statements about a good result. Judging them
|
|
requires running the prompt and assessing what comes back, which CPF does not
|
|
specify and most consumers cannot do. They are **declared, not run** — the
|
|
same division as `include` and `derive` in § 10.4, and for the same reason.
|
|
|
|
#### Results are not part of the package
|
|
|
|
An eval file declares what to assess; it MUST NOT record outcomes. Results are
|
|
run evidence, which lives outside the immutable package (§ 17) and may be
|
|
associated with `<id>@<version>` by a registry or evaluation system without
|
|
mutating it. A tool reporting results SHOULD identify the package version, the
|
|
eval `name`, and each check's outcome.
|
|
|
|
## 13. Provenance and lineage
|
|
|
|
```yaml
|
|
provenance:
|
|
author: Ada Example
|
|
source: https://example.invalid/source
|
|
derived_from:
|
|
- id: review/code-review
|
|
version: 1.1.0
|
|
```
|
|
|
|
The field is descriptive. Registries SHOULD preserve provenance when publishing or mirroring packages.
|
|
|
|
## 14. Licensing
|
|
|
|
A package MAY declare an SPDX license identifier or other clear license expression:
|
|
|
|
```yaml
|
|
license: CC-BY-4.0
|
|
```
|
|
|
|
Absence of a license MUST NOT be interpreted as permission to redistribute or modify the package.
|
|
|
|
Tools SHOULD surface licensing metadata during publishing and installation.
|
|
|
|
## 15. Tags
|
|
|
|
```yaml
|
|
tags:
|
|
- architecture
|
|
- review
|
|
- agentic-coding
|
|
```
|
|
|
|
Tags are free-form discovery hints. Registries MAY normalize or enrich tags while preserving package metadata.
|
|
|
|
## 16. Extensions
|
|
|
|
`extensions` is the designated escape hatch for experimental or implementation-specific metadata.
|
|
|
|
```yaml
|
|
extensions:
|
|
org.example.canned-prompts:
|
|
maturity: experimental
|
|
```
|
|
|
|
Extension keys SHOULD be namespaced to avoid collisions.
|
|
|
|
A consumer MUST ignore unknown extension entries unless it explicitly claims support for them.
|
|
|
|
## 17. Immutability and versioning
|
|
|
|
Published `<id>@<version>` pairs SHOULD be immutable.
|
|
|
|
A registry SHOULD reject publication of a package when the same ID/version already exists with different contents unless an explicit administrative override mechanism exists.
|
|
|
|
Immutability is scoped to a registry, because identity is (§ 3.2). The same
|
|
`<id>@<version>` held by two registries is two packages, and a consumer holding
|
|
both is not in a conflict — it is holding two things whose names happen to
|
|
coincide. Only a repeat publication *within one registry* violates
|
|
immutability.
|
|
|
|
### 17.1 Precedence and prereleases
|
|
|
|
Where versions are compared, precedence follows Semantic Versioning: numeric
|
|
fields first, and a prerelease version ranks **below** its own release, so
|
|
`1.0.0-rc1` precedes `1.0.0`. Build metadata does not affect precedence.
|
|
|
|
A prerelease is **not selected** by `any`, `newest`, or a `>=` lower bound
|
|
(§ 10.3). Only an exact pin selects one. Publishing a release candidate
|
|
therefore never changes what existing consumers resolve to — which is the
|
|
point of marking it a candidate.
|
|
|
|
Suggested versioning guidance:
|
|
|
|
- PATCH: wording/metadata correction with intended behavior unchanged;
|
|
- MINOR: backward-compatible behavior or parameter additions;
|
|
- MAJOR: changed contract, renamed/removed inputs, or materially different intended behavior.
|
|
|
|
This guidance is intentionally advisory because prompt behavior is probabilistic and cannot be versioned as mechanically as an API.
|
|
|
|
## 18. Package validation
|
|
|
|
A validator SHOULD verify at least:
|
|
|
|
1. `prompt.yaml` exists and parses as YAML;
|
|
2. required manifest fields exist;
|
|
3. `format` names a recognized revision (§ 3.2);
|
|
4. `id` is non-empty and contains no path traversal;
|
|
5. `version` is non-empty;
|
|
6. `template` resolves to a regular file inside the package;
|
|
7. referenced example/eval paths do not escape the package;
|
|
8. required inputs and parameter names are unique;
|
|
9. every template placeholder resolves to a declared input or parameter;
|
|
10. no required value is silently omitted during rendering;
|
|
11. no input declares both `default` and `required: true`;
|
|
12. a derived default declares either a `derive` reference or an inline
|
|
`derive.prompt`, never both;
|
|
13. a `derive` or `include` reference names a package declared in
|
|
`dependencies.prompts`;
|
|
14. no default declares both `include` and `derive`;
|
|
15. every dependency referenced by a composition or derived default declares a
|
|
`version`, and that version is a semver literal, `any`, `newest`, or a
|
|
`>=` lower bound (§ 10.3);
|
|
16. inclusion does not form a cycle;
|
|
17. every eval file parses and declares a `schema`;
|
|
18. an eval declaring `canned-prompts/eval-rubric/v0.1` has a `name`, asserts
|
|
something via `render` or `output`, uses only known render checks, and —
|
|
when it declares an `example` — names a path listed in the manifest's
|
|
`examples`;
|
|
19. every `dependencies.context` entry declares a `name` and a `description`,
|
|
and a `requirement` of `required` or `optional` if present;
|
|
20. capability names in `dependencies.capabilities` and
|
|
`compatibility.capabilities` are lowercase kebab-case.
|
|
|
|
A validator SHOULD additionally warn when a package intended for publication
|
|
declares an inline derivation prompt (§ 6.1).
|
|
|
|
A validator that is given a **registry** rather than a package SHOULD verify,
|
|
when `registry.yaml` is present, that `format` is
|
|
`canned-prompt-registry/v0.1`, that `name` is a non-empty string usable in a
|
|
qualified reference, and that each `namespaces` entry declares a `policy` of
|
|
`open` or `closed`.
|
|
|
|
## 19. Security requirements
|
|
|
|
Prompt packages are content, not trusted code.
|
|
|
|
Implementations MUST NOT:
|
|
|
|
- execute code merely because it appears in a package;
|
|
- treat template expressions as arbitrary code;
|
|
- treat a derived default's prompt text as instructions addressed to the
|
|
consuming tool itself; it is content to be resolved on the package's behalf,
|
|
and it carries no more authority than any other package text;
|
|
- derive an input default without the caller being able to see that it
|
|
happened (§ 5.1 rule 6);
|
|
- interpolate environment variables or credentials implicitly;
|
|
- follow paths outside the package without explicit user action;
|
|
- embed or require secrets in published package metadata.
|
|
|
|
Implementations SHOULD:
|
|
|
|
- inspect all referenced paths for traversal;
|
|
- make package contents visible before execution;
|
|
- surface provenance and license metadata;
|
|
- treat remote content referenced by a package as untrusted input;
|
|
- separate package installation from model/tool authorization.
|
|
|
|
## 20. Registry model
|
|
|
|
CPF does not mandate registry transport.
|
|
|
|
A valid registry may be:
|
|
|
|
- a filesystem directory;
|
|
- a Git repository;
|
|
- an object store;
|
|
- an HTTP service;
|
|
- a federated catalog.
|
|
|
|
Conceptually, a registry stores immutable package versions keyed by:
|
|
|
|
```text
|
|
<id>@<version>
|
|
```
|
|
|
|
### 20.1 Registry identity and namespace ownership
|
|
|
|
A registry MAY declare itself with a `registry.yaml` at its root:
|
|
|
|
```yaml
|
|
format: canned-prompt-registry/v0.1
|
|
name: house
|
|
description: Internal prompt registry.
|
|
|
|
namespaces:
|
|
practice:
|
|
owner: Ada Example
|
|
policy: closed
|
|
scratch:
|
|
policy: open
|
|
```
|
|
|
|
Fields:
|
|
|
|
| Field | Required | Meaning |
|
|
|---|---:|---|
|
|
| `format` | yes | MUST be `canned-prompt-registry/v0.1` |
|
|
| `name` | yes | Short registry name, used in qualified references (§ 3.2) |
|
|
| `description` | no | Human-readable explanation |
|
|
| `namespaces` | no | Mapping of namespace to its claim |
|
|
|
|
Within `namespaces`, `owner` is a human-readable claim and `policy` is
|
|
`closed` (only the owner publishes) or `open` (anyone may). Both are
|
|
descriptive: a filesystem registry has no way to authenticate a publisher, and
|
|
authentication, signing and trust scoring are all explicit non-goals.
|
|
|
|
The file is **optional**. A bare directory remains a valid registry; a consumer
|
|
that finds no manifest SHOULD take the registry's name from how it was
|
|
addressed — for the reference implementation, the registry directory's
|
|
basename.
|
|
|
|
**Ownership is a property of the registry, not of the package.** A package
|
|
never declares who owns its namespace. This keeps the claim where it can
|
|
actually be acted on — the registry decides what it admits — and keeps
|
|
packages free of unverifiable assertions of authority, consistent with § 19's
|
|
position that a package is content rather than a trusted actor. It also means
|
|
package semantics do not change when a filesystem registry is later replaced
|
|
by a hosted one.
|
|
|
|
A registry SHOULD refuse to publish into a `closed` namespace it does not
|
|
consider the publisher to own. How it decides is registry policy and is
|
|
outside this specification.
|
|
|
|
### 20.2 Consumer-side layout
|
|
|
|
A consumer drawing on more than one registry MUST keep packages from different
|
|
registries distinct, because identity is registry-scoped (§ 3.2). Installing
|
|
the same `<id>@<version>` from two registries is not an error and MUST NOT
|
|
overwrite: both are retained and addressed by qualified reference.
|
|
|
|
The reference implementation stores its catalog as:
|
|
|
|
```text
|
|
catalog/
|
|
└── <registry name>/
|
|
└── <id path>/
|
|
└── <version>/
|
|
```
|
|
|
|
The reference implementation uses the filesystem layout:
|
|
|
|
```text
|
|
registry/
|
|
└── <id path>/
|
|
└── <version>/
|
|
├── prompt.yaml
|
|
└── ...
|
|
```
|
|
|
|
For example:
|
|
|
|
```text
|
|
registry/
|
|
├── registry.yaml
|
|
└── practice/
|
|
└── pqrst-estimate/
|
|
└── 0.1.0/
|
|
├── prompt.yaml
|
|
└── prompt.md
|
|
```
|
|
|
|
A registry's own layout is not namespaced by registry name: within one
|
|
registry, an id is unambiguous by definition.
|
|
|
|
### 20.3 The index
|
|
|
|
A store MAY keep an `index.yaml` at its root recording which package versions
|
|
entered it, from where, and when:
|
|
|
|
```yaml
|
|
format: canned-prompt-index/v0.1
|
|
entries:
|
|
- registry: local
|
|
id: helix/repo-orient
|
|
version: 0.1.0
|
|
name: Repo Orientation
|
|
source: /home/worsch/helix-forge/prompts/repo-orient
|
|
method: add
|
|
included_at: "2026-09-06T13:31:02Z"
|
|
declared_author: Bernd Worsch
|
|
declared_source: personal prompt collection, contributed 2026-09-06
|
|
license: MIT
|
|
```
|
|
|
|
This is deliberately **not** package data. `provenance` (§ 13) records who wrote
|
|
a prompt and where the idea came from; the index records how a copy arrived in
|
|
*this* store — a fact about the store, not about the artifact, and one that
|
|
would differ for every consumer. Keeping it outside preserves immutability
|
|
(§ 17): recording an arrival never rewrites the package that arrived.
|
|
|
|
| Field | Meaning |
|
|
|---|---|
|
|
| `registry`, `id`, `version` | Which package version this entry is about |
|
|
| `source` | Where the copy came from: a path, a registry, a URL |
|
|
| `method` | How it arrived: `add`, `install`, `publish` |
|
|
| `included_at` | When it **first** entered this store |
|
|
| `last_seen_at` | When it was most recently re-recorded, if ever |
|
|
| `declared_author`, `declared_source` | Copied from the package's own `provenance`, so the index is readable without opening every package |
|
|
| `license` | Copied from the manifest, so licensing is visible in a listing |
|
|
|
|
`included_at` records first arrival and MUST NOT be overwritten when the same
|
|
`registry`/`id`/`version` is recorded again; a re-run updates `last_seen_at`
|
|
instead. When a package first entered a collection is a fact about history, not
|
|
about the last time someone ran a command.
|
|
|
|
Because identity is registry-scoped (§ 3.2), the same `id@version` from two
|
|
registries is two entries, not a conflict.
|
|
|
|
## 21. Reference CLI semantics
|
|
|
|
The reference tool uses two stores:
|
|
|
|
- **catalog** — packages locally available for search/show/render;
|
|
- **registry** — packages available for publish/install.
|
|
|
|
Commands:
|
|
|
|
```text
|
|
add PATH validate and copy a package into the local catalog
|
|
search QUERY search locally installed package metadata
|
|
show ID display one installed package manifest
|
|
resolve ID report the resolved value of every input and parameter
|
|
render ID render an installed prompt with supplied values
|
|
publish PATH validate and copy a package into a filesystem registry
|
|
install ID copy a package version from the registry into the catalog
|
|
```
|
|
|
|
Every command that takes an `ID` accepts either a bare id or a qualified
|
|
`<registry>:<id>` reference (§ 3.2). A bare id that matches packages installed
|
|
from more than one registry is reported as ambiguous, listing the candidates,
|
|
rather than resolved by guessing.
|
|
|
|
`add` takes a package from a path rather than from a registry, so it files the
|
|
package under the reserved registry name `local`.
|
|
|
|
The reference tool satisfies `include` defaults, because inclusion is
|
|
deterministic and needs no model, and reports `derive` defaults it cannot
|
|
satisfy.
|
|
|
|
```text
|
|
eval ID run an installed package's render checks
|
|
index [ID] show what entered this catalog, from where and when
|
|
```
|
|
|
|
`eval` runs the deterministic render checks of every recognized eval file and
|
|
reports output criteria as declared but not run.
|
|
|
|
The reference tool never calls a model, so its `resolve` handles supplied
|
|
values and static defaults only and reports any input whose derived default it
|
|
cannot satisfy. `render` performs the same resolution and then substitutes;
|
|
per § 5.1 rule 10 it never derives.
|
|
|
|
These semantics are illustrative, not mandatory for other implementations.
|
|
|
|
## 22. Worked example
|
|
|
|
This is `examples/pqrst-estimate` in the `canned-prompts` repository, abridged.
|
|
It packages a prompt whose governing document requires it be used *unmodified*,
|
|
so the package's job is fidelity: the default render must equal the source
|
|
byte for byte, and an eval enforces that.
|
|
|
|
`prompt.yaml`:
|
|
|
|
```yaml
|
|
format: canned-prompt/v0.2
|
|
id: practice/pqrst-estimate
|
|
name: PQRST Estimate
|
|
version: 1.0.0
|
|
summary: The canonical end-of-session PQRST effort audit.
|
|
template: prompt.md
|
|
|
|
inputs:
|
|
- name: add_ons
|
|
type: content
|
|
required: false
|
|
description: Optional text appended after the canonical block.
|
|
default: ''
|
|
|
|
output:
|
|
format: text
|
|
description: A PQRST-Estimate record.
|
|
|
|
license: MIT
|
|
|
|
examples: [examples/basic.yaml, examples/with-rationale.yaml]
|
|
evals: [evals/canonical-fidelity.yaml]
|
|
|
|
tags: [pqrst, retrospective, agentic-coding]
|
|
|
|
provenance:
|
|
author: pqrst-practice
|
|
source: ~/pqrst-practice/PqrstPrompt.md
|
|
```
|
|
|
|
The source prompt documents two optional add-ons appended after the main block.
|
|
CPF has no conditionals (§ 5), so they are not expressed as a flag: `add_ons` is
|
|
an input whose default is the empty string, and each sanctioned add-on is an
|
|
example fixture. The default render is therefore the source prompt exactly, and
|
|
`examples/with-rationale.yaml` supplies one add-on when a reader wants it.
|
|
|
|
`evals/canonical-fidelity.yaml` guards that property — `resolves_all`, the
|
|
canonical dimension names and rules, and `not_contains` checks naming the
|
|
paraphrase this package once was (§ 12.1). Composition is illustrated separately
|
|
in § 10.4.
|
|
|
|
## 23. Open questions
|
|
|
|
### Settled since v0.1
|
|
|
|
`CANP-WP-0002` promoted five items from "experience will decide" to decisions.
|
|
Each is now specified. This table records where the rule lives and what was
|
|
chosen, so a later reader can find the reasoning and not just the rule.
|
|
|
|
| Question | Decision | Where |
|
|
|---|---|---|
|
|
| Optional inputs were unusable | `default` on inputs, static or derived; resolution separated from rendering | § 5.1, § 6.1 |
|
|
| Registry namespaces and ownership | Identity is registry-scoped; ownership is registry policy, never a package's own claim | § 3.2, § 20.1, § 20.2 |
|
|
| Prompt composition and inheritance | Composition by reference in two kinds, `include` and `derive`; no inheritance | § 10.3, § 10.4 |
|
|
| Canonical evaluation schemas | One schema, `canned-prompts/eval-rubric/v0.1`; render checks run, output criteria are declared | § 12.1 |
|
|
| Typed context and dependency contracts | `dependencies` means required, `compatibility` means observed; `context` names what CPF cannot package | § 9.1, § 10.1, § 10.2 |
|
|
|
|
Two habits recur across those decisions, and later revisions should follow them
|
|
rather than rediscover them:
|
|
|
|
**Separate the deterministic half from the rest.** `include` and `derive`,
|
|
render checks and output criteria, resolve and render. Each pair splits at the
|
|
same seam: what a tool can do with the package alone, and what needs a model. A
|
|
consumer that cannot call a model is never second-class — it does the
|
|
deterministic half completely and reports the rest honestly, rather than
|
|
guessing or silently producing something incomplete.
|
|
|
|
**A package never asserts what it cannot back.** Ownership belongs to the
|
|
registry that admits a package, not to the package that would like to claim a
|
|
namespace. `compatibility` records observation, never permission. A derived
|
|
default is a request to a consumer, not an instruction the package executes.
|
|
This is why § 19 can treat a package as content rather than as an actor.
|
|
|
|
### Still deferred
|
|
|
|
Experience should still determine whether later revisions standardize:
|
|
|
|
- content macros;
|
|
- cryptographic integrity and signing;
|
|
- model capability vocabularies — § 10.2 keeps capability names free-form,
|
|
validated for shape and not for membership;
|
|
- run manifests and evidence formats;
|
|
- deterministic compilation manifests;
|
|
- trust and reputation signals;
|
|
- federated discovery;
|
|
- richer template syntax;
|
|
- pattern-matching render checks — § 12.1 stops at `contains`, `not_contains`
|
|
and `resolves_all` rather than adding a matching language to a format whose
|
|
§ 5 rests on not having one.
|
|
|
|
### Decided against
|
|
|
|
Template inheritance (§ 10.4) is not deferred; it was considered and refused.
|
|
Reopening it means overturning a decision, not filling a gap, and would have to
|
|
answer the four objections recorded there.
|
|
|
|
Until practical usage forces these questions, the format should remain
|
|
intentionally small.
|