diff --git a/docs/roadmap/promptkit.md b/docs/roadmap/promptkit.md index 1b94214..12c4400 100644 --- a/docs/roadmap/promptkit.md +++ b/docs/roadmap/promptkit.md @@ -1,8 +1,7 @@ # Adopt PromptKit v0.14.0 and expose comparison and catalogs -Status: proposed feature end state; implementation has not started. The scope -and ownership direction are agreed. Catalog API and presentation choices remain -under [Open Decisions](#open-decisions). +Status: accepted feature end state; implementation has not started. Scope, +ownership, catalog API, and initial presentation choices are settled. ## Purpose and authority @@ -31,15 +30,17 @@ and [ADR 0012](../adr/0012-typed-configuration-comparison-pairs.md) govern captu declarations and input/state lifetimes. Existing deliberately selected contracts control; prototype implementation shapes receive no compatibility preference. -This is a feature roadmap, not a staged coding assignment. A later implementation -plan should sequence the work after the open decisions are resolved. Only this -roadmap is added in the present pass; it does not upgrade dependencies, revise -ADRs, change current behavior documentation, or run Go tests. +This roadmap defines the selected end state. A later implementation plan should +sequence the work. The present pass updates only this roadmap. ## Current baseline Baseline: CommandKit commit `ab270e2`. +CommandKit is a prerelease alpha codebase with no existing consumers. The +maintained consumer examples demonstrate intended usage; this adoption needs no +consumer migration plan. + | Owner | Current state | | --- | --- | | Core | Go 1.26.0; declarations, registration, typed bindings, dispatch, help/version, diagnostics, and outcomes. Cobra/pflag remain internal. No optional owning-library dependency. ReleaseKit v0.4.0 is the declared maintainer tool. | @@ -178,10 +179,9 @@ app promptkit list profiles Each command accepts configuration/overlay selection and the applicable existing suite domain selectors, without requiring a definition ID or exact-version operand. These commands use the namespace's engine selection, rather than a -new configuration-scope selector. Catalog report formats and YAML shape remain -the presentation decisions below. No filtering, pagination, version-priority -rule, requirement discovery, or per-definition readiness check is added in this -delivery. +new configuration-scope selector. Catalogs use the initial YAML presentation +defined below. No filtering, pagination, version-priority rule, requirement +discovery, or per-definition readiness check is added in this delivery. The bundled adapter obtains prompt ID/version pairs with `Engine.ListPrompts` and profile IDs with `Engine.ListProfiles`. It preserves returned identities @@ -191,18 +191,27 @@ membership, include maintained definitions that remain effective, and order identities lexically; prompt versions are not ranked semantically. Upstream remains authoritative if its adopted contract evolves. -Successful empty catalogs produce an empty collection under the selected format. -They do not fail because there are no definitions. Membership does not prove -execution readiness. Identifiers retain their exact values, including values +Successful empty catalogs render as `[]`. Both nil and allocated empty slices +returned by a successful provider represent an empty inventory. Membership does +not prove execution readiness. Identifiers retain their exact values, including values that require YAML quoting; CommandKit does not normalize identifiers or promise that catalog data is safe for arbitrary public disclosure. ### Consumer and invocation end state -Add independently optional catalog providers to `ckprompt.Suite[I, S]`, using -`commandkit.Acquired[[]promptkit.PromptIdentity]` and -`commandkit.Acquired[[]string]` as their results. Reuse meaningful upstream public -types. The request shape recommendation is under OD-1. +Add independently optional catalog providers to `ckprompt.Suite[I, S]` with these +signatures: + +```go +ListPrompts func(context.Context, ckconfig.Selection, I, S) (commandkit.Acquired[[]promptkit.PromptIdentity], error) +ListProfiles func(context.Context, ckconfig.Selection, I, S) (commandkit.Acquired[[]string], error) +``` + +Catalog commands have no selected definition ID or version. Their standard +selection data fits `ckconfig.Selection`; domain values belong in `I`. Direct +selection input matches the engine loader and existing `Suite.CheckInput` +contract. A separate catalog request wrapper would add no information today. +Results reuse meaningful upstream public types. `FromEngine(loadEngine)` supplies both catalog callbacks alongside the existing named-inspection callbacks. It acquires an engine only when the selected catalog @@ -214,6 +223,10 @@ callbacks retain their own effects. `Command(suite)` captures metadata, bindings, and callback references and emits only supplied operations. Listing can be installed without either named-show callback; named-show operations can remain installed without catalog callbacks. +Emit each intermediate group only when it has supplied operations: a catalog-only +suite has no `show` group, and a show-only suite has no `list` group, including in +help output. + An entirely absent suite contributes no namespace or commands, while attached construction errors are still reported. A nonempty family remains root-only and owns its namespace under the existing installation contract. Importing ckprompt @@ -228,6 +241,52 @@ version invoke neither suite factories nor providers; operator-requested listing does acquire its selected inventory. Use existing usage/operational outcomes, diagnostic delivery, cancellation boundaries, and write-failure handling. +### Selecting capabilities + +The bundled adapters supply all supported operations: `FromEngine` supplies both +catalogs and both named inspections, and `ConfigScope` includes comparison. +Applications can narrow these declarations before passing them to `Command`. +For example, given an application engine loader `loadEngine`, a show-only +definition suite and a configuration scope limited to show and validate are: + +```go +definitions := ckprompt.FromEngine(loadEngine) +definitions.ListPrompts = nil +definitions.ListProfiles = nil + +scope := ckprompt.ConfigScope(loadEngine) +scope.Operations = []ckconfig.Operation{ckconfig.Show, ckconfig.Validate} +``` + +### Initial catalog presentation + +Deliver YAML only, default to YAML, and accept explicit `--format yaml`. Catalog +sequences are readable for operators and directly usable by automation. YAML +preserves arbitrary identity strings without a separate text escaping convention. +These are initial catalog presentation choices; additional formats can follow +operator needs. Existing named-show formats remain available. + +Emit one bare sequence per invocation. Prompt entries have explicit `id` and +`version` string fields; profile entries are strings. For example: + +```yaml +- id: briefing + version: "1" +- id: briefing + version: "2" +``` + +```yaml +- autumn +- spring +``` + +The command path identifies the resource, so a bare collection is simple to +consume without an envelope for unused metadata. Preserve provider order and +exact strings; quote through the YAML encoder rather than interpreting +numeric-looking versions. CommandKit defines these report fields explicitly; +serialization of an upstream Go struct does not define the CLI schema. + ## Work needed from the baseline ### Dependencies and distribution @@ -251,12 +310,16 @@ diagnostic delivery, cancellation boundaries, and write-failure handling. - Extend `ConfigScope` with the native PromptKit comparison provider, retaining ordinary acquisition and appropriate side diagnostics. Route results through the existing ckconfig comparison implementation. +- Adapt diagnostic acquisition for comparison deliberately. The current + `loadPromptKitEngine` helper uses a single `promptkit` scope label and can + return on cancellation before collecting inspection diagnostics. Account for + side labels, source legends, and retained diagnostics at failure and + cancellation boundaries when reusing or adjusting it. - Extend `Suite`, `FromEngine`, and family assembly for independent prompt/profile catalog providers. Use core declarations and typed binding composition for selection and input preparation; add no second parser. -- Implement catalog presentation after OD-2 and OD-3 are resolved. Define - CommandKit-owned report fields explicitly instead of treating serialization of - an upstream Go struct as a permanent CLI schema. Preserve upstream values. +- Implement the selected catalog YAML presentation, including `[]` for both nil + and allocated empty successful results. - Keep implementation proportionate. Reuse existing acquisition, preparation, diagnostic, YAML, and outcome helpers where they fit; introduce only the concrete helper changes needed for the new operations. @@ -268,16 +331,18 @@ diagnostic delivery, cancellation boundaries, and write-failure handling. configurations yield meaningfully different engine inspections. Its cache choices remain example choices, not policy for consumers. - When behavior lands, update owning GoDoc, the CLI reference, consumer guidance, - module README, and internal overview. Replace claims that PromptKit comparison + module README, and internal overview. Document the bundled adapters' complete + operation sets and how to narrow them. Replace claims that PromptKit comparison and catalogs are unavailable. Reconcile the completed ConfigKit roadmap's PromptKit status and the deferred-work record; retain requirement inspection as explicitly deferred without inventing its future syntax. - Validate existing show/validate/sources/explain behavior, named prompt/profile reports, app comparison, and the composed domain command against the upgraded dependency. Add focused evidence for catalog-only and mixed capabilities, - callback-free help, input/state timing, exact identities and versions, empty - inventories, native comparison, diagnostics retained across side failures, - cancellation, and report delivery failures. + callback-free help with absent intermediate groups omitted, input/state timing, + exact identities and versions, nil and allocated empty inventories, native + comparison, diagnostics retained across side failures, cancellation, and report + delivery failures. - Prefer assembled behavior and real fast native collaborators. Reuse ckconfig's existing report/lifecycle coverage; do not duplicate ConfigKit's comparator or PromptKit's full catalog suite, freeze private layout or polling counts, or @@ -303,79 +368,5 @@ selectors, assertion statuses, JSON output, new scope aggregation, and backend changes remain outside this delivery. Completion requires all selected capabilities and relevant dependency metadata, -notices, docs, examples, and boundary validation. Resolve the open decisions -before producing a decision-complete implementation plan. Recommendations below -are proposals, not already accepted CLI or Go contracts. - -## Open Decisions - -### OD-1: Catalog callback request shape - -**Recommendation:** Add `ListPrompts` and `ListProfiles` fields with direct -`ckconfig.Selection` input, separate `I` and `S`, and the existing acquisition -convention. The proposed signatures are: - -```go -ListPrompts func(context.Context, ckconfig.Selection, I, S) (commandkit.Acquired[[]promptkit.PromptIdentity], error) -ListProfiles func(context.Context, ckconfig.Selection, I, S) (commandkit.Acquired[[]string], error) -``` - -Catalog commands have no selected definition ID or version. Their only standard -selection data is already represented by `ckconfig.Selection`; domain values -belong in `I`. This keeps the API small and matches the existing engine-loader -shape without adding a request wrapper solely for speculative future fields. - -**Alternative:** Introduce a ckprompt-owned `CatalogRequest` containing -`Selection`, and use it for both callbacks. This matches the request-object -style of existing named-inspection providers and creates a place for future -catalog-specific options. It is viable, but adds a public type with no additional -information today. Choose it if that consistent provider shape is judged more -valuable than the narrower current surface; neither choice requires a core API -change. - -### OD-2: Catalog report formats and default - -**Recommendation:** Deliver YAML only, default to YAML, and accept explicit -`--format yaml`. Catalog sequences are readable for operators and directly -usable by automation. This keeps one presentation path, preserves arbitrary -identity strings without designing a separate escaping convention, and follows -the recent comparison report's deliberately small format scope. This is a -recommendation for these new commands, not a policy that all families must use -the same formats. - -**Alternative:** Support text and YAML, defaulting to text as existing -`promptkit show` commands do. One profile per line and prompt ID/version columns -are convenient for terminal use and keep the namespace's format defaults more -uniform. The cost is a second renderer and a decision about unambiguous display -of identities containing whitespace or line breaks. YAML-only listings can still -coexist with the established show-command formats without changing them. - -### OD-3: YAML catalog document shape - -**Recommendation:** Emit one bare sequence per invocation. Prompt entries have -explicit `id` and `version` string fields; profile entries are strings. For -example: - -```yaml -- id: briefing - version: "1" -- id: briefing - version: "2" -``` - -```yaml -- autumn -- spring -``` - -An empty inventory renders as `[]`. The command path already identifies the -resource, so a bare collection is simple to consume and does not add an unused -metadata framework. Preserve provider order and exact strings; quote through -the YAML encoder rather than interpreting numeric-looking versions. - -**Alternative:** Wrap the collections under `prompts:` and `profiles:` keys. -This gives each report a self-describing resource label and leaves room for -later metadata without changing the root type. It is a reasonable choice if -reports will routinely be stored without their command context. It also adds -nesting and anticipates metadata this delivery does not need; an empty report -would be `prompts: []` or `profiles: []` instead of a bare empty sequence. +notices, docs, examples, and boundary validation. The decisions needed for an +implementation plan are settled.