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
236 lines
8.8 KiB
Markdown
236 lines
8.8 KiB
Markdown
# canned-prompts seed
|
|
|
|
> **Collect, reuse and share prompts and prompt templates.**
|
|
|
|
This bundle contains a first project seed for `canned-prompts`:
|
|
|
|
- [`INTENT.md`](INTENT.md) — project mission, boundaries, principles, and success criteria.
|
|
- [`CannedPromptFormat.md`](CannedPromptFormat.md) — the package-format specification, currently revision v0.2.
|
|
- [`reference/`](reference/) — deliberately small Python CLI implementing the basic lifecycle.
|
|
- [`examples/pqrst-estimate/`](examples/pqrst-estimate/) — a real package that can be used to exercise the implementation.
|
|
- [`examples/house-style/`](examples/house-style/) — a `type: fragment` package that `pqrst-estimate` composes.
|
|
|
|
## Try the reference implementation
|
|
|
|
```bash
|
|
cd reference
|
|
python -m venv .venv
|
|
. .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
pip install -r requirements.txt
|
|
|
|
# add the included examples to your local catalog
|
|
python canned_prompts.py add ../examples/house-style
|
|
python canned_prompts.py add ../examples/pqrst-estimate
|
|
|
|
# find and inspect it
|
|
python canned_prompts.py search pqrst
|
|
python canned_prompts.py show practice/pqrst-estimate
|
|
|
|
# see how each input and parameter resolves, and where the value came from
|
|
python canned_prompts.py resolve practice/pqrst-estimate \
|
|
--set session_summary="Implemented feature X, read unfamiliar code, added tests."
|
|
|
|
# render it
|
|
python canned_prompts.py render practice/pqrst-estimate \
|
|
--set session_summary="Implemented feature X, read unfamiliar code, added tests."
|
|
|
|
# publish it to the local filesystem registry
|
|
python canned_prompts.py publish ../examples/pqrst-estimate
|
|
|
|
# remove the local catalog if you want to simulate another machine, then install
|
|
python canned_prompts.py install practice/pqrst-estimate --version 0.1.0
|
|
```
|
|
|
|
Packages added from a path are filed under the registry name `local`; packages
|
|
installed from a registry are filed under that registry's name. `search` prints
|
|
qualified references:
|
|
|
|
```text
|
|
house:practice/pqrst-estimate@0.1.0 PQRST Estimate
|
|
local:practice/pqrst-estimate@0.1.0 PQRST Estimate
|
|
```
|
|
|
|
By default the reference tool uses:
|
|
|
|
```text
|
|
~/.canned-prompts/catalog
|
|
~/.canned-prompts/registry
|
|
```
|
|
|
|
Override them with:
|
|
|
|
```text
|
|
CANNED_PROMPTS_HOME=/some/path
|
|
```
|
|
|
|
or command-level `--catalog` / `--registry` options.
|
|
|
|
## Resolution vs rendering
|
|
|
|
The format separates the two steps (`CannedPromptFormat.md` § 5.1).
|
|
Resolution decides a value for every input and parameter and may be
|
|
non-deterministic; rendering substitutes those values and always is. An input
|
|
may declare a default that is either a static value or a *derived* one — a
|
|
prompt that a capable consumer may run to produce the value, declared without
|
|
naming any resolver or model.
|
|
|
|
This reference tool never calls a model, so it resolves supplied values and
|
|
static defaults only, and reports anything it cannot derive instead of
|
|
rendering a prompt with a silent hole in it.
|
|
|
|
## Composition
|
|
|
|
A package composes another by declaring it as a dependency and binding it to an
|
|
input default. There are two kinds:
|
|
|
|
- **`include`** — inline the other package's *rendered template* as text.
|
|
Deterministic, needs no model, and the reference CLI performs it.
|
|
- **`derive`** — use the other package's *result*, obtained by running it.
|
|
Only a consumer able to run it can supply one.
|
|
|
|
`examples/pqrst-estimate` includes `examples/house-style`, so a shared style
|
|
block is a versioned package rather than copied text:
|
|
|
|
```yaml
|
|
dependencies:
|
|
prompts:
|
|
- id: practice/house-style
|
|
version: ">= 0.1.0"
|
|
requirement: required
|
|
|
|
inputs:
|
|
- name: house_style
|
|
required: false
|
|
default:
|
|
include: practice/house-style
|
|
```
|
|
|
|
A dependency pins an exact version by default; `any`, `newest` and a `>= X.Y.Z`
|
|
lower bound are explicit opt-ins. These are per-dependency selectors, not
|
|
version ranges — there is no solver, and constraint resolution across a
|
|
dependency graph remains a non-goal.
|
|
|
|
There is no template inheritance. A package never extends another or overrides
|
|
its parts; composition is by reference only, so a package's content stays
|
|
readable without chasing ancestors.
|
|
|
|
## Evals
|
|
|
|
An eval file declares what to assess. `evals/` used to hold whatever an author
|
|
put there; it now has one schema the tooling understands, split along the same
|
|
line as composition:
|
|
|
|
- **render checks** — deterministic assertions about the *rendered prompt*
|
|
(`contains`, `not_contains`, `resolves_all`). No model needed, so the
|
|
reference CLI runs them.
|
|
- **output criteria** — statements about a good *result*. Declared, not run.
|
|
|
|
```bash
|
|
python canned_prompts.py eval practice/pqrst-estimate
|
|
```
|
|
|
|
```text
|
|
local:practice/pqrst-estimate@0.2.0
|
|
evals/quality.yaml (pqrst-estimate-quality)
|
|
render PASS contains "must sum to exactly 100%"
|
|
render PASS resolves_all
|
|
output -- 4 criteria declared (not run: judging output needs a model)
|
|
```
|
|
|
|
An eval declares assessment, never results. Results are run evidence and live
|
|
outside the immutable package.
|
|
|
|
## Required versus compatible
|
|
|
|
Two fields used to say overlapping things about capabilities. They now differ
|
|
in one word each:
|
|
|
|
| Field | Meaning | Absence means |
|
|
|-------|---------|---------------|
|
|
| `dependencies` | **required** — does not work without it | a consumer should warn or refuse |
|
|
| `compatibility` | **observed** — known to work with it | nothing; it is information |
|
|
|
|
Dependencies come in three kinds, separated by what the format can do about
|
|
them: `prompts` are packages it resolves by id and version, `context` names
|
|
things it does not package at all (an information space, an API, a corpus the
|
|
caller supplies), and `capabilities` are what the environment must be able to
|
|
do. `resolve` lists the last two, since the reference tool cannot verify
|
|
either:
|
|
|
|
```text
|
|
requires (this tool cannot verify these):
|
|
capability web-search
|
|
context repository-tree — A listing of the repository under review.
|
|
```
|
|
|
|
## Registries and identity
|
|
|
|
An id names a package *within a registry* (`CannedPromptFormat.md`
|
|
§ 3.2). The same id obtained from two registries may be two different
|
|
packages, so the catalog keeps them apart and a bare id that matches more than
|
|
one is reported as ambiguous rather than guessed. Qualify it when you need to:
|
|
|
|
```bash
|
|
python canned_prompts.py render house:practice/pqrst-estimate --set ...
|
|
```
|
|
|
|
A registry may describe itself with an optional `registry.yaml` naming it and
|
|
recording which namespaces are claimed and under what policy. Those claims are
|
|
descriptive: a filesystem registry cannot authenticate a publisher, and
|
|
signing and trust scoring are explicit non-goals. Ownership lives with the
|
|
registry rather than in the package, so no package carries an unverifiable
|
|
assertion of authority.
|
|
|
|
## The index
|
|
|
|
Every store keeps an `index.yaml` recording which package versions entered it,
|
|
from where, and when:
|
|
|
|
```bash
|
|
python canned_prompts.py index
|
|
```
|
|
|
|
```text
|
|
local:helix/repo-orient@0.1.0 2026-09-06T13:31:02Z add
|
|
from /home/worsch/helix-forge/prompts/repo-orient
|
|
declares source personal prompt collection, contributed 2026-09-06
|
|
```
|
|
|
|
This is store metadata, not package data. `provenance` records who wrote a
|
|
prompt; the index records how a copy arrived *here* — which differs for every
|
|
consumer, and which must never rewrite the package it describes. `included_at`
|
|
is first arrival and is never overwritten; a re-run updates `last_seen_at`.
|
|
|
|
## Dependencies are reported, not fetched
|
|
|
|
Installing a package that composes another warns when the dependency is
|
|
absent, including when it is present but no version matches:
|
|
|
|
```text
|
|
declared dependencies not in this catalog: practice/house-style@>= 0.1.0
|
|
— install them, or composition referencing them will not resolve
|
|
```
|
|
|
|
Nothing is fetched automatically. Dependency resolution is left to the
|
|
consumer, but a package that installs cleanly and then cannot render is worse
|
|
than one that says what it is waiting for.
|
|
|
|
## Packaging and versions
|
|
|
|
`add`, `publish` and `install` copy the reserved paths (`prompt.yaml`,
|
|
`prompt.md`, `README.md`, `LICENSE`, `examples/`, `evals/`, `assets/`) plus
|
|
anything a manifest field references — and nothing else, as § 2 requires. What
|
|
was left behind is reported rather than silently dropped:
|
|
|
|
```text
|
|
not packaged (not a reserved path, not referenced by the manifest): .git/, .venv/, notes.txt
|
|
```
|
|
|
|
Version precedence follows SemVer, so `1.0.0` outranks `1.0.0-rc1`, and
|
|
`any`, `newest` and `>= X.Y.Z` skip prereleases entirely. Publishing a release
|
|
candidate never changes what existing consumers resolve to; name it exactly to
|
|
use it.
|
|
|
|
## Deliberate limitations
|
|
|
|
This seed has no hosted registry, model execution, authentication, network access, dependency resolver, or social features. `publish` and `install` operate on a filesystem registry so that the package semantics can be tested before infrastructure is built around them.
|