# canned-prompts reference CLI This is intentionally a **small reference implementation**, not the intended final architecture. It demonstrates eight verbs: ```text 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: ```text ~/.canned-prompts/catalog ~/.canned-prompts/registry ``` A **registry** stores packages flat, because an id is unambiguous within one registry: ```text ///... ``` 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: ```text ////... ``` For example: ```text ~/.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 `:`. 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`, `publish` and `install` copy 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`, `newest` and `>=` skip prereleases entirely. Only an exact pin selects one. - `install` copies from registry to catalog. - `add` copies a package directly to catalog. - `search`, `show`, `resolve`, and `render` operate on catalog packages, and print qualified `:` references. - `include` defaults are satisfied (inclusion is deterministic); `derive` defaults are reported, not run. Inclusion cycles are detected and named. - `eval` runs the deterministic render checks of any eval declaring the `canned-prompts/eval-rubric/v0.1` schema, and reports output criteria as declared but not run. Unrecognized schemas are skipped, not rejected. A failed render check exits non-zero. - `resolve` lists required capabilities and context dependencies, which this tool cannot verify, rather than implying it checked them. - An optional `registry.yaml` names a registry and records namespace claims. `publish` warns when a namespace is declared `closed` — 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, `resolve` reports the input as unresolved and `render` refuses rather than substituting empty text. Use this implementation to challenge the format. Replace it once real usage reveals the right architecture.