Found while verifying the repo against INTENT.md's eight success criteria for a first practical release, after CANP-WP-0002 finished. Criterion 5 is "publish a version to a registry and install it elsewhere". Installing practice/pqrst-estimate into a fresh catalog reported success, and rendering it then failed with "included package not found: practice/house-style". CANP-WP-0002-T03 introduced this — composition made a package installable but unrenderable, and nothing said so at install time. The error was honest, but reaching it after a successful-looking install is the silently-incomplete failure section 23 now names as the thing this format avoids. `add` and `install` now name declared prompt dependencies the target catalog cannot satisfy, including a package present at no matching version. They do not fetch anything: section 10 leaves dependency resolution to the consumer, and auto-installing transitively is a resolver — a separate decision from refusing to hand over a package that looks fine and is not. Whether `install` should offer `--with-dependencies` is left open as a design question rather than smuggled in as a bug fix. Tests 81 -> 84. Recorded as CANP-WP-ADHOC-2026-09-06. 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
3.8 KiB
canned-prompts reference CLI
This is intentionally a small reference implementation, not the intended final architecture.
It demonstrates eight verbs:
add PATH
search QUERY
show ID
resolve ID --set key=value
render ID --set key=value
eval ID
install ID [--version VERSION]
publish PATH
The implementation uses a local catalog plus a filesystem registry and performs no model calls.
resolve and render are separate because the specification separates them
(§ 5.1): resolution decides each value and may be non-deterministic, rendering
substitutes and always is. resolve prints where every value came from —
supplied, default, or fallback — before any prompt is produced.
Stores
Default locations:
~/.canned-prompts/catalog
~/.canned-prompts/registry
A registry stores packages flat, because an id is unambiguous within one registry:
<registry>/<id path>/<version>/...
A catalog is namespaced by registry, because identity is registry-scoped (§ 3.2) and the same id may be installed from more than one place:
<catalog>/<registry name>/<id path>/<version>/...
For example:
~/.canned-prompts/catalog/house/practice/pqrst-estimate/0.1.0/
~/.canned-prompts/catalog/local/practice/pqrst-estimate/0.1.0/
A registry's name comes from its optional registry.yaml, and otherwise from
its directory basename. add takes a package from a path rather than a
registry, so it files it under local (override with --as).
Commands that take an ID accept a bare id or a qualified <registry>:<id>.
A bare id installed from more than one registry is reported as ambiguous
rather than resolved by guessing.
Design choices
- YAML manifest via PyYAML.
{{ name }}template substitution only.- No arbitrary expression/code execution.
- Published versions are immutable by default.
add,publishandinstallcopy only reserved paths and manifest- referenced files. A working directory's.git, virtualenv or scratch files never ship; whatever is left out is named on stderr.- Version precedence follows SemVer: a prerelease ranks below its release, and
any,newestand>=skip prereleases entirely. Only an exact pin selects one. installcopies from registry to catalog.addcopies a package directly to catalog.search,show,resolve, andrenderoperate on catalog packages, and print qualified<registry>:<id>references.includedefaults are satisfied (inclusion is deterministic);derivedefaults are reported, not run. Inclusion cycles are detected and named.evalruns the deterministic render checks of any eval declaring thecanned-prompts/eval-rubric/v0.1schema, and reports output criteria as declared but not run. Unrecognized schemas are skipped, not rejected. A failed render check exits non-zero.resolvelists required capabilities and context dependencies, which this tool cannot verify, rather than implying it checked them.addandinstallname declared prompt dependencies the catalog cannot satisfy. They do not fetch them — resolution is the consumer's job (§ 10) — but a package that looks installed and cannot render should say so.- An optional
registry.yamlnames a registry and records namespace claims.publishwarns when a namespace is declaredclosed— it cannot authenticate a publisher, and says so rather than implying it checked. - Static input defaults are applied; derived defaults (§ 6.1) are not. This
tool never calls a model, so a derived default is satisfied only by its
static fallback
value. Without one,resolvereports the input as unresolved andrenderrefuses rather than substituting empty text.
Use this implementation to challenge the format. Replace it once real usage reveals the right architecture.