# Configuration Collections Implementation Plan Status: ready for implementation; no feature changes are implemented by this plan. Implement the accepted [feature roadmap](configuration-collections.md). That document owns intent, scope, and selected policy; this document owns API delivery choices and the ordered implementation steps. Each numbered stage is sized as one prompt for a Luna coding agent. Complete stages in order. Foundation and migration stages are parts of one refactor, not separately publishable releases. ## Baseline And Working Rules Reviewed PromptKit baseline: `683689a4f89d0fea6a8e0c6faf5830414adf9c7b`. It selects ConfigKit `v0.7.1`, both `/v3` provider catalogs at `v3.20261013.0`, and the completed smoke-test implementation and remediations. The existing implementation plan described that completed work; Git retains it. This plan replaces it without reopening the smoke-test design. ConfigKit `v0.8.0` resolves to commit `137769f3f18a370c68444242fb5d88e620e307e5` (the annotated tag object is distinct). Its released public contracts in `docs/config.md`, release notes, and ADRs 0011–0014 supply the required placement and shared version-check behavior. The adjacent checkout is a reference, not a committed build dependency. Before each stage, inspect status, preserve unrelated work, read the owning implementation/tests, and follow [development orientation](../development.md). Apply the [agent](../policy/agents.md), [architecture](../policy/architecture.md), [testing](../policy/testing.md), [documentation](../policy/documentation.md), [OSS](../policy/oss.md), and relevant [release](../policy/release.md) policies. Use the repository's code-discovery instructions. Reuse unchanged readings. Update affected GoDoc and canonical contracts as each behavior lands; Stage 17 is a consistency pass, not permission to leave current documentation stale. Record completion and validation beneath the stage, then commit each completed, nonempty unit with a short plain-English message. These stages change PromptKit; external collection publishing is separate work. Do not push, tag, release, or introduce committed workspace/replacement files. The sprint requires neither publication of a new catalog nor a live provider. Dependency acquisition is setup, separate from offline behavioral validation. Maintain [ADR 0001](../adr/0001-configuration-boundary.md): ConfigKit owns source processing, composition, inheritance, and header checking through its configured version callback. PromptKit interprets final effective values and their resource contexts. Do not inspect contributions or source history to enforce domain validity, including in tests. Explicit operator inspection remains available. Preserve execution, retry/repair, credentials, appended messages, capacity, observations, cancellation, and prepared-handle semantics except for the accepted identity/version changes. Introduce no installer, implicit discovery, new provider protocol, cross-collection inheritance resolver, compatibility alias bundle, live reload, or additional release gate. ## Delivery Decisions These names and signatures settle delivery details left by the feature roadmap. Private helper names below are implementation guidance, not public invariants. ### Final Configuration And Runtime Identity Use a typed root document with optional `version`, root `backends`, `profiles`, and `prompts`, and `collections`. Each collection body has optional `release_version` and the same three resource mappings. Root and collection resource maps are keyed by local ID; `prompts` maps directly to definitions, not another version map. Keep ordinary strict ConfigKit decoding and existing definition rules. Collection bodies are mappings; an empty body is useful. Represent source-root `version`, collection `release_version`, and prompt `version` with `*string` in the typed document. Configure `Definition.Version.Path = configkit.Keys("version")` and `SourceVersionModeIfPresent`. The checker accepts absence, accepts exact text `1` from a string or strict decimal integer, and rejects explicit null or other texts with a safe ConfigKit diagnostic. ConfigKit owns type checking and non-main header consumption. Do not synthesize a main input or declaration. Collection release and prompt labels are opaque strings: nil means absent/null, and a non-nil empty string remains explicitly declared. Do not trim, order, interpret as SemVer, or require these labels. Keep the retained ConfigKit result in its authored effective shape. Refactor configuration helpers to receive the effective resource base path rather than reconstructing it from a runtime ID. Visit root and collection mappings with their actual paths; after handoff, index each resource under its full public ID. Do not flatten/re-key the ConfigKit result or make a second load. Presence, normalization records, content-file origins, secret classification, explanations, and diffs must keep the effective paths, including `collections/`. Create shared private identity helpers under `internal/domain`. Follow the roadmap's exact grammar: a nonblank unqualified ID has no slash; a qualified reference has exactly one slash and two nonempty components. A configured local key is nonblank and slash-free. A collection namespace is nonblank and slash-free, using the same syntax as a nonempty scope. Preserve spelling, including otherwise permitted whitespace, dots, case, and punctuation. Add no other character whitelist. Never apply this grammar to models, paths, URLs, artifact/input names, session IDs, or descriptive labels. Validate final configured resource keys and effective PromptKit references. Retain existing existence/readiness timing: for example, profile backend existence is checked as today, but an unselected backend diagnostic default is not made eagerly resolvable. ConfigKit interprets `extends` as a sibling key, not a PromptKit qualified reference. PromptKit does not validate or reinterpret consumed inheritance directives. ### Prompt Selection And Optional Labels Remove `PromptVersion` from public/internal `RunRequest`, `RequirementInspectionRequest`, and `SmokeTestRequest`. `ValidateRequest`, `Prepare`, and `PrepareExecution` continue to use `RunRequest`. Change `InspectPrompt` to: ```go func (e *Engine) InspectPrompt(ctx context.Context, promptID string) (*PromptInspection, error) ``` All prompt repository, compiled-template, and requirement-snapshot lookups use ID alone. Remove ambiguity tracking, version selectors, version ordering, and request assertions. Keep `PromptIdentity.ID`; change `PromptIdentity.Version` to `*string`. Keep output field names `PromptVersion`, changing their types to `*string` wherever they describe the selected label: prepared details, run results, prompt/requirement inspection, execution events, and smoke-test targets. The internal definition uses `Version *string` with equivalent semantics. Each returned mutable pointer is owned by its result, including events and prepared snapshots. JSON `omitempty` omits nil while preserving a declared empty string. Preserve other existing serialization choices. The optional label remains part of captured definition metadata and its existing definition-hash projection. Copy the pointer; do not dereference it as a cache or selection key. No cross-release hash-stability promise is introduced. Derive automatic structured-output schema names from the selected prompt ID using the existing sanitization, not from a version-selection token. Keep explicit schema selection and structural validation behavior unchanged. ### Immutable Scope On The Existing Engine ```go type Namespaces struct { Prompt string Profile string Backend string } func (e *Engine) WithNamespaces(namespaces Namespaces) (*Engine, error) ``` Return another engine facade over the same assembled engine components with immutable scope values. An internal engine view may be a shallow copy containing the same runner, smoke tester, inspection, and inventory collaborators. It does not invoke `NewEngine` or build another capacity manager. `WithNamespaces` replaces all three scopes on the new view; empty fields clear those scopes. The receiver is unchanged. Validate syntax, not namespace existence. Use the existing invalid-configuration convention for an invalid engine or scope. At the internal engine entry boundary, use shared qualification helpers for caller-supplied IDs. Validate supplied syntax; leave omitted optional IDs empty; qualify slashless nonempty IDs for the applicable scope; pass qualified IDs unchanged. The runner continues exact lookup. Do not requalify configured default profiles, backend references, sibling inheritance, or diagnostic defaults. Apply the same policy to `Run`, `Prepare`, `PrepareExecution`, `ValidateRequest`, `InspectPrompt`, `InspectProfile`, `InspectRequirements`, and all three selection fields of `SmokeTest`. `ValidateRequest` already delegates to preparation; use that route rather than adding another validator. `RunPrepared` consumes its captured selection without qualification. Preserve its existing runner-ownership check; scope does not introduce another handle owner. `InspectConfiguration` continues to expose the complete retained configuration, not a filtered/re-keyed view. Results and observer metadata carry full selected identities. ### Listing Filters And Inventory Use one concrete optional filter argument for profile, prompt, and new backend listings: ```go type NamespaceFilterMode uint8 const ( NamespaceDefault NamespaceFilterMode = iota NamespaceNamed NamespaceUnqualified NamespaceAll ) type NamespaceFilter struct { Mode NamespaceFilterMode Name string // Used only by NamespaceNamed. } func (e *Engine) ListProfiles(ctx context.Context, filter ...NamespaceFilter) ([]string, error) func (e *Engine) ListPrompts(ctx context.Context, filter ...NamespaceFilter) ([]PromptIdentity, error) func (e *Engine) ListBackends(ctx context.Context, filter ...NamespaceFilter) ([]string, error) ``` Zero or one filter is accepted; multiple filters or an unknown mode return the ordinary invalid-request error rather than guessing precedence. Omission and a zero filter mean default: use that resource's scope, or all resources when it is unset. Named requires a nonempty valid namespace. Unqualified selects IDs without a slash; All includes every ID. A non-Named mode ignores `Name`. An explicit filter replaces, not intersects, the view's default for that call. Keep IDs full, sort lexically by full ID, and retain existing context, ownership, and empty-list behavior. Copy optional labels on returned prompt entries. Qualified results can be reused through any view. To select an unqualified ID returned by an explicit All/Unqualified filter, use the original engine or a view without that resource scope; a listing filter never changes execution scope. Add the following small discovery surfaces: ```go type ResourceKind string const ( ResourcePrompt ResourceKind = "prompt" ResourceProfile ResourceKind = "profile" ResourceBackend ResourceKind = "backend" ) func (e *Engine) ListNamespaces(ctx context.Context, kinds ...ResourceKind) ([]string, error) type CollectionInfo struct { Namespace string ReleaseVersion *string } func (e *Engine) ListCollections(ctx context.Context) ([]CollectionInfo, error) ``` No kinds means the union of all three resource types. Supplied kinds select their union; repeats are harmless and unknown kinds are invalid requests. Namespace enumeration describes resource membership across the captured engine, independent of view scopes. Return distinct named namespaces sorted lexically; exclude the unqualified group. Collection inventory likewise covers the entire captured `collections` mapping, sorted by namespace, including metadata-only and resource-only entries. It is not filtered by a view and does not include an invented root collection. Both surfaces use the existing listing-style nil-engine and context error conventions and return detached values. They do not inspect historical sources, reopen files, or assert package authenticity. Capture sorted inventories once at construction. Namespace buckets or sorted ranges may avoid repeated full scans for filtered listings. Prefer a single resource traversal plus sorting and ordinary indexed lookups; no repeated ConfigKit queries, definition deep copies for identity-only listings, global caches, or performance/complexity promises in the public API are needed. ### Collection Input Convenience ```go func CollectionInput(namespace string, source configkit.Source) (configkit.Input, error) ``` Validate the required namespace syntax and return an input with that source, `Destination: configkit.Keys("collections", namespace)`, and `Imports: true`. Invalid namespace syntax returns an error matching `ErrInvalidConfig`. Do not open/read the source or infer a namespace/filename. ConfigKit still owns source validity and loading errors. The caller may change the returned input's imports, filesystem context, or destination, or construct an input directly. This supports host, embedded, and mapping sources with one helper, without introducing another loader or options framework. Directory/Filesystem helpers retain their existing explicit discovery and imports-disabled semantics. `ProfileSource` and `BackendSource` retain their root-document shapes and can be mounted with this helper. Direct local-key fragments use explicit ConfigKit destinations that include the resource category. ### Migration Choices Do not mass-copy the provider inventories into PromptKit or create a mandatory replacement bundle. Provide synthetic, complete collection examples and guidance for adapting selected existing catalog configuration. Adjacent repositories and their publication are outside this sprint. The reviewed pinned catalog assets have slash-free profile keys, so these explicit mappings are collision-free within those assets: | Previous identity | Documented migration identity | | --- | --- | | Backend `openrouter` | `openrouter/default` | | Backend `rakestrawhome` | `rakestrawhome/default` | | Each OpenRouter catalog profile `p` | `openrouter/p`, retaining the exact local key `p` | | Profile `rakestrawhome-gemma-4-31b` | `rakestrawhome/rakestrawhome-gemma-4-31b` | | Built-in `promptkit-openrouter-standard` | No automatic replacement; optional caller profile `openrouter/standard` | | Built-in `promptkit-openrouter-auto` | No automatic replacement; optional caller profile `openrouter/auto` | These are documented conversions, not installed aliases. Simply mounting old `/v3` assets does not update their stored backend/profile references; those references and diagnostic defaults need the explicit edits shown here. For an optional caller standard profile, `extends: gemini-flash-latest` is valid only within the same `openrouter` profiles mapping containing that base. The caller auto profile may explicitly set backend `openrouter/default` and model `openrouter/auto`. Neither name becomes a PromptKit promise. Move backend diagnostic defaults to exact new profile IDs. Preserve endpoint/settings and provider model strings, including the pinned Gemini model's leading `~`. Application-specific IDs require a deliberate collision review, not automatic slash-to-dot replacement. For a formerly multi-version prompt, its maintainer chooses the installed definition; examples use the single definition already present. Put its old version string into optional metadata where useful. Do not select a winner from a consumer's multi-version history by guessed ordering. Document exact references, paths, backend capacity identity changes, source-root header reservations, label null/empty semantics, and the loss of cross-mapping inheritance. Migration documentation is not a runtime migration tool. ## Stage 1: Adopt The Released ConfigKit Prerequisite Scope: dependency selection and existing integration compatibility only. 1. Select ConfigKit `v0.8.0` with normal Go module tooling; update `go.mod` and `go.sum` without filesystem replacements. Verify the selected release commit and notices; update its attribution entry with the full commit above. 2. Check affected keyed literals and source-inspection handling for upstream additions. `SourceInfo` is no longer comparable; compare relevant fields if PromptKit currently relies on comparability. Do not enable new schema behavior. 3. Leave Go's consumer minimum at `1.26.0` unless the selected dependency actually requires a higher minimum. Leave unrelated dependencies/tooling unchanged. Validation: `GOWORK=off go test ./internal/configuration .` and the three offline examples, including configuration inspection/diff coverage. This stage establishes the unchanged PromptKit baseline on the new dependency. Completion: ConfigKit `v0.8.0` is selected at commit `137769f3f18a370c68444242fb5d88e620e307e5`; its attribution links and module checksums are updated. The Go consumer minimum remains `1.26.0`. No `SourceInfo` comparability-dependent code required adjustment. Validation passed: `GOWORK=off go test ./internal/configuration .` and `GOWORK=off python3 scripts/check-examples.py`. ## Stage 2: Add Shared Resource Naming Primitives Scope: small private domain helpers and focused behavior tests. 1. Implement exact ID parsing/validation, namespace syntax validation, local-key validation, qualification, and namespace extraction as needed by later stages. Keep omission policy in operation callers, not a universal required-ID rule. 2. Cover unqualified/dotted names, qualified bypass, missing/empty scope, malformed slash forms, and preserved spelling. Check that namespace matching is exact rather than a prefix match. 3. Do not wire names into all public operations yet or export a splitting API. Validation: `GOWORK=off go test ./internal/domain`. Test selected naming behavior, not a helper call sequence or invented character restrictions. Completion: private resource-ID, namespace, local-key, qualification, and namespace-extraction helpers are implemented with focused grammar and spelling tests. Validation passed: `GOWORK=off go test ./internal/domain` and `git diff --check`. ## Stage 3: Make Configuration Processing Path-Aware Scope: preparation refactor inside `internal/configuration`; current format stays. 1. Refactor `captureFields`, `resolveBackends`, `resolveProfiles`, `validateEffective`, prompt metadata capture, and prompt materialization to accept/use explicit effective base paths. Preserve current values and errors. 2. Carry a resource's public ID separately from its ConfigKit path. Stop deriving an effective path by splitting a runtime ID. Use ConfigKit path segments for literal keys and preserve inherited `content_file` origins. 3. Factor resource-map traversal only as needed to reuse the same processing for root and collection mappings later. Do not add a generic visitor framework. 4. Prepare the existing provider-secret predicate to recognize actual resource paths without mistaking arbitrary nested `extra_params` data for resources. Keep its existing protected-key policy. Validation: configuration load, target, prompt-origin, inheritance, and inspection tests; `GOWORK=off go test ./internal/configuration .`. A behavior-preserving refactor should not rewrite unrelated expectations. Completion: configuration capture, normalization, effective validation, and prompt materialization now receive explicit ConfigKit base paths. Existing resource IDs remain independent from those paths; source-origin reads and the protected provider-key policy are preserved. Validation passed: `GOWORK=off go test ./internal/configuration .`. ## Stage 4: Install One Prompt Definition Per ID Scope: prompt storage format, materialization, and fixture-format migration. 1. Change root `prompts` to `map[string]promptConfig`; add nullable `Version *string` to the raw prompt definition. Materialize one entry per ID, preserving the label text without normalization or a generated label. 2. Remove nested version indexes, ambiguity tracking, and selection-by-version from the configuration adapter. Use the actual prompt path without the old version segment for metadata and message resources. 3. To keep this stage bounded, existing repository method parameters and public selector fields may remain only until Stage 5. At this adapter boundary their temporary implementation delegates to ID-only lookup; do not compare them with labels or create an assertion mode. Existing string-valued output labels are converted to presence-aware values in Stage 6. These are migration seams, not new compatibility behavior to retain or publish. 4. Mechanically migrate YAML fixtures, mapping builders, and example configuration files to the direct definition shape. Move retained version keys to quoted metadata. Replace tests of parallel versions/ambiguity with one-entry lookup and ordinary mapping-overlay cases. Keep unrelated validation coverage. Validation: `GOWORK=off go test ./...`, including consumers of migrated fixtures. Test ID-only selection, source-relative content, and inherited/overlaid prompt settings. Do not add tests preserving temporary obsolete selector parameters. Completion: prompts now map directly from each ID to one definition, with an optional descriptive version label. Configuration lookup and message/input metadata paths are ID-only; ambiguity handling and version-keyed indexes are removed. Fixtures, examples, and the canonical format reference use the direct shape, including layered overlays. Validation passed: `GOWORK=off go test ./...`, `GOWORK=off python3 scripts/check-examples.py`, and `git diff --check`. ## Stage 5: Remove Request-Side Version Selection Scope: compile-directed removal of obsolete selector plumbing; no new lookup rules. 1. Remove request `PromptVersion` fields and the version parameter from public `InspectPrompt` and internal prompt repository/snapshot/template interfaces. Update runner preparation, inspection, requirements, and smoke selection. 2. Update public-to-internal conversion, redacted formatting, fakes, tests, examples, and call sites. Remove version-without-prompt checks and the transitional signatures from Stage 4. Preserve ordinary not-found identities. 3. Use the selected prompt ID for generated structured-schema names; retain the existing sanitization and explicit schema behavior. Do not remove output metadata fields merely because selectors are gone. 4. Update affected GoDoc now so obsolete selectors are no longer advertised. Validation: `GOWORK=off go test ./...` and focused vet of modified packages. Search declarations/call sites for remaining selection/ambiguity logic; descriptive label references are valid and should not be blanket-deleted. Completion: request-side version selectors and version parameters have been removed from prompt lookup, inspection, requirement analysis, and smoke-test selection. Generated structured-schema names now derive from the prompt ID; result-side descriptive label fields remain. Updated the consumer guide and GoDoc to reflect ID-only selection. Validation passed: `GOWORK=off go test ./...`, focused `GOWORK=off go vet` for modified packages, `GOWORK=off python3 scripts/check-examples.py`, and `git diff --check`. ## Stage 6: Carry Optional Prompt Labels Through Results Scope: presence-aware metadata across internal values and the facade. 1. Change internal definition `Version` and all selected-label output fields identified above to `*string`. Read the raw optional field captured by Stage 4. Update conversion and ownership copies, hashing projection, requirement snapshots, observation selection/events, prepared details/results, and smoke target projection. Optional labels never become lookup keys. 2. Distinguish nil from a declared empty string in inspection/listings and JSON. Both omitted and null mean no label; a higher-layer or inherited null clears the label through ordinary ConfigKit composition. 3. Update the example summary types and test expectations. Add focused boundary coverage for absence, null clearing, empty/exact text, and pointer ownership; reuse existing report/prepared/event detachment tests where practical. Validation: domain, promptdef, configuration, observation, usecase, and root tests; `GOWORK=off go test ./...` and the offline examples. Verify the existing selected definition hash still agrees between inspection and preparation. Completion: prompt labels are presence-aware from configuration capture through inspection, listing, requirements, prepared and completed runs, observation events, and smoke targets. Nil and declared-empty labels remain distinct in JSON; null overlays clear inherited labels. Returned label pointers are independently owned, and inspection/preparation retain matching definition hashes. Validation passed: `GOWORK=off go test ./...`, `GOWORK=off go vet ./...`, `GOWORK=off python3 scripts/check-examples.py`, and `git diff --check`. ## Stage 7: Enable Shared Specification Checking Scope: root declaration policy through ConfigKit's released version API. 1. Add optional root `version` to the typed document. Configure the version rule and `SourceVersionModeIfPresent` with the exact checker specified above. Keep no-main and headerless sources valid. 2. Use ConfigKit's header consumption and source evidence without a source pre-parser, validation loop, or PromptKit mode option. Nested prompt labels remain ordinary metadata. 3. Cover accepted string/integer `1`, omitted main/header, rejected null or unsupported declarations, consumed non-main headers, and an explicit main declaration retained in inspection. A headerless imported prompt fragment still undergoes ordinary final-value validation. Validation: focused real-ConfigKit tests in `internal/configuration` and public construction/inspection tests. Do not replicate upstream's full version-type or import matrix. Run `GOWORK=off go test ./internal/configuration .`. Completion: the optional root declaration is checked through ConfigKit's shared source-version API, accepting only exact string or integer `1` while allowing absence and preserving the main declaration in inspection. Accepted underlay declarations are consumed; null and unsupported values produce safe diagnostics, and headerless payloads still receive final-value validation. Validation passed: `GOWORK=off go test ./internal/configuration .`. ## Stage 8: Assemble And Index Final Collection Resources Scope: namespaced schema, final resource interpretation, and runtime indexes. 1. Add `collections` and collection `release_version`/resource mappings to the typed document. Visit root and collection maps using Stage 3's effective paths. Validate namespaces/local keys; build full IDs only in runtime indexes. 2. Include backend/profile snapshots and prompt metadata/templates in that traversal. Keep the retained ConfigKit result structurally unchanged. Preserve the distinction between root unqualified and collection-local keys. Migrate maintained qualified-key fixtures into collection/local-key mappings, updating exact references and inspection paths together. Use ordinary explicit destinations until the convenience helper lands; do not keep a second root spelling for qualified identities. 3. Validate effective references with the naming helper and existing existence policy. Local `extends` stays with ConfigKit. Do not reject repeated namespace contributions, require collection releases, or qualify stored references. 4. Extend secret-path matching to backend/profile extras beneath collections, preserving the existing protected-key list. Use exact effective paths for field presence, normalization, `content_file`, explanations, and diagnostics. 5. Preserve backend-ID capacity policy wiring. The same final backend is one capacity identity regardless of the sources that contributed its settings. Validation: focused real-ConfigKit tests for two collections with duplicate local names, root resources, partial overrides, inherited relative content, explicit zero/null settings, and redacted namespaced provider data. Include retained release metadata, sibling inheritance, headerless collection fragments, resources named `version` in nested mappings, and header/declaration distinctions. Run `GOWORK=off go test ./internal/configuration .`. ## Stage 9: Make Application Tests Independent Of Bundled Catalogs Scope: owned fixtures and examples that currently assume automatic provider data. 1. Locate tests/examples using bundled backend/profile IDs, inherited catalog settings, default smoke profiles, or baseline listing counts. Supply the explicit synthetic definitions each behavior needs through existing sources. 2. Keep generic test helpers small and local; no full catalog snapshot or shared test fixture framework. HTTP adapter tests may retain provider adapter names but use controlled transports and synthetic configuration. 3. Keep catalog-specific assembly tests until Stage 10 removes the integration. Do not preserve provider inventory assertions as application contracts. Validation: the affected root, engine, and usecase tests plus examples. Ordinary coverage should now express its own backend, profile, and prompt requirements. ## Stage 10: Remove Automatic Catalogs And Built-In Profiles Scope: engine composition, dependency/notices cleanup, and the retired promise. 1. Remove `catalog.Underlays()` from `internal/engine.New`; load only caller underlays and optional main. Preserve their order and strict-group semantics. Empty configuration constructs an engine with empty resource inventories. 2. Delete `internal/catalog`, its owned profiles, and integration-specific tests after checking references. Do not delete generic file-discovery helpers. 3. Remove both catalog module requirements and unused checksums through module tooling. Do not update/publish those repositories or copy their inventories into PromptKit as a replacement. 4. Update attribution for actual retained material; remove catalog dependency entries when nothing incorporated remains. Keep a notice if other copied material still requires it. Do not strip a shared license text still in use. 5. Retire the release policy's catalog-update exception and literal built-in-name promise. Apply ordinary compatibility rules to PromptKit format/API changes; independently selected configuration is no longer a bundled release inventory. Update architecture/internal inventory and current format documentation for the removed component. Preserve historical release notes. Validation: `GOWORK=off go test ./...`; verify empty inventories, explicit former backend names still work when configured, and inference smoke tests retain their selection/capability behavior with caller-supplied metadata. Review `go.mod`, `go.sum`, imports, and notices for residual automatic catalog coupling. ## Stage 11: Add The Explicit Collection Input Helper Scope: the single public convenience function and its GoDoc. 1. Implement `CollectionInput` exactly as specified above, reusing namespace validation and existing facade error conventions. It creates an input, not an engine and not a configuration pre-parser. 2. Keep raw ConfigKit inputs and existing directory/filesystem/programmatic helpers usable. Do not reinterpret their IDs or introduce root discovery. 3. Add one native-file and one embedded/mapping assembled case with entry imports and a later deliberate override. Verify resource contexts survive. Validation: source-helper contract tests and focused configuration/root tests. Verify helper construction itself performs no source read using an existing controlled source seam where needed, rather than adding a production interface. ## Stage 12: Add Immutable Scopes To Ordinary Execution Scope: public `Namespaces`/`WithNamespaces` and shared engine-boundary routing. 1. Add the public facade and internal immutable view. Replace all scopes on each new view without mutating its receiver. Reuse assembled collaborators. 2. Route caller prompt/profile selections in `Run`, `Prepare`, and `PrepareExecution` through shared qualification. `ValidateRequest` follows its current preparation route. Stored defaults and omitted IDs stay untouched. 3. Preserve resolved full IDs through prepared details, results, events, errors, and selected backend identity. Leave `RunPrepared` captured and single-claim; do not add a scope mismatch check or rebuild shared state. 4. Add public behavior tests for two independent prompt/profile scopes, qualified bypass, no fallback, absent well-formed namespaces, and invalid scope syntax. Assert the receiver retains its original behavior. Validation: root/prepared/usecase tests and focused race-enabled scope tests. Use injected generation or a controlled HTTP boundary; never a live endpoint. ## Stage 13: Apply Scopes To Inspection And Diagnostics Scope: complete the existing operation inventory without a second resolver. 1. Route `InspectPrompt`, `InspectProfile`, and `InspectRequirements` through the same helpers; resolve each request's explicitly supplied prompt/profile fields independently. Keep configured references exact. 2. Route `SmokeTest`'s supplied PromptID, ProfileID, and BackendID by their own scopes before ordinary diagnostic selection. Keep its precedence, optional omissions, backend defaults, factual reports, and errors unchanged. 3. Keep `InspectConfiguration`/Diff global with effective ConfigKit paths. Do not qualify schema paths, provider models, input identifiers, or overrides. 4. Review all public resource-selection entry points for omissions. Validate malformed supplied reference syntax through the existing invalid-argument boundary; retain ordinary not-found behavior for well-formed missing IDs. Validation: representative public inspection/requirements/validation/smoke cases prove shared behavior and full identities. Reuse naming-helper tests instead of duplicating the full syntax matrix in every API test. Run relevant root/engine tests and focused race checks. ## Stage 14: Add Backend Listing And Namespace Filters Scope: the existing identity-inventory path, not the execution runner. 1. Add the filter declarations and optional arguments to profile/prompt listing; add backend identity listing through configuration, internal engine, and facade. Existing no-filter engine calls still enumerate everything. 2. Resolve default/explicit filters once per listing using the relevant view scope. Validate named filters and modes; filter exact namespace membership. Use captured sorted inventories, optionally indexed by namespace. 3. Return full IDs and detached optional prompt labels, with existing cancellation and empty-result behavior. Do not materialize definitions for identity listing. Validation: extend listing tests with scoped defaults, explicit named/All/ Unqualified overrides, no-scope defaults, absent namespaces, same-prefix namespace names, full-ID round trips (and unqualified selection through the original engine), invalid filters, ownership, and canceled contexts. Use a compact matrix across resource types, not three copies of all tests. Run configuration/root tests. ## Stage 15: Expose Namespace And Effective Collection Inventories Scope: the two discovery APIs and construction-time inventory capture. 1. Capture namespace sets by resource kind from final indexed IDs; implement `ListNamespaces` with the chosen union, kind validation, and global semantics. 2. Capture `CollectionInfo` values from final `collections` declarations. Preserve absent/null versus empty/exact release labels, including metadata-only and resource-only collections. Copy label pointers on output. 3. Delegate through the internal engine's narrow inventory boundary and root facade. Do not derive collection releases from source header evidence or confuse resource namespace membership with collection declarations. Validation: one representative inventory fixture covers cross-kind membership, deduplication/sorting, unqualified exclusion, metadata-only collections, scope-independent enumeration, effective overrides, cancellation, and ownership. Run configuration/root tests; no file access or generation should be needed. ## Stage 16: Maintain Complete Consumer And Migration Examples Scope: runnable/synthetic examples and precise migration guidance. 1. Keep the existing prepare/run/observe examples valid with ID-only selection and optional labels. Extend the preparation example, or its existing input assets, to demonstrate two collections, explicit input selection, a scoped view, filtering, and operator inventory without a provider call. Keep the run/observe examples focused on their distinct existing workflows. 2. Add small complete collection entry/fragments under `examples/`, with optional headers/releases, source-relative message content, exact stored references, sibling inheritance, and an intentional later partial override. Use synthetic endpoints/models rather than another maintained provider catalog. 3. Add `docs/consumers/configuration-migration.md` explaining the breaking format and signatures, the explicit mapping table above, optional caller standard/auto choices, and deployment selection responsibility. Do not promise arbitrary consumer migrations are automatic or validate upstream provider availability. 4. Update semantic example checks only for the changed example outputs. If script logic changes, run its focused checks; do not rewrite release tooling. Validation: `GOWORK=off python3 scripts/check-examples.py`. Assemble the maintained collection example through real ConfigKit and PromptKit. Keep copied material's actual attribution obligations aligned if any is introduced. ## Stage 17: Finalize Canonical Contracts And Migration Documentation Scope: documentation consistency after the APIs and examples exist. 1. Update GoDoc for all changed/new public declarations, errors, optional labels, ownership, scopes, and listing behavior. Do not leave obsolete selectors or an implication that a descriptive label controls execution. 2. Update `docs/formats.md` for the final schema, specification header policy, source-root reservations, one installed prompt, exact references, local inheritance, and explicit provider configuration. Keep current contracts here, not in the migration guide or roadmap. 3. Update `docs/consumers/pkg-promptkit.md`, README quickstart/navigation, `docs/internal/sources.md`, internal inventory, and affected runner/rendering/ observation documents. Explain unchanged resource contexts and operator-only provenance use. Remove live claims about automatically bundled inventories. 4. Review architecture, release policy/procedure, development reading guidance, and attribution for obsolete catalog assumptions. Revise only affected local statements; do not rewrite upstream policy language unnecessarily or weaken ordinary compatibility promises. Do not revise historical release notes or immutable ADR decisions. Validation: review changed Markdown links and example references, check GoDoc against declarations, and run `git diff --check`. Release notes and version/tag selection belong to the later requested release preparation, not this stage. ## Stage 18: Verify Cross-Boundary Behavior And Close The Sprint Scope: focused integration gaps and final regression validation, not new features. 1. Trace the feature roadmap's acceptance criteria to focused existing/new tests. Add only missing assembled-boundary coverage. One synthetic fixture can prove independent collection names, scoped execution/inspection, full-ID filtering, exact defaults, optional labels, and inventory without duplicating every assertion at each internal layer. 2. Use a controlled concurrent model boundary to verify ordinary and differently scoped calls share the same configured backend's capacity. Reuse existing admission/cancellation tests for queue mechanics. Verify prepared selections remain captured when another view is used; no namespace is mutable global state. 3. Confirm final-value-only validation, source-local headers versus ordinary metadata, retained inherited/overlaid content origins, and redaction under namespaced paths. Final inspection still describes ConfigKit's original effective shape rather than a rewritten runtime index. 4. Remove all temporary selector signatures/adapters from the migration stages. Review source/tests/docs for old version-key maps, version selection/assertions, automatic catalog contributions, mandatory built-in names, and local module replacements. Historical notes and optional metadata references may remain. 5. Run the final offline checks once for the resulting content: ```sh GOWORK=off go test -race ./... GOWORK=off go vet ./... GOWORK=off python3 scripts/check-examples.py git diff --check ``` Format changed Go files and validate affected Markdown links. Review the full diff/status for unintended files and private data; commit the completed unit. Mark this plan and the feature roadmap complete, leaving retirement to normal release preparation. Do not publish, wait for CI, probe providers, or introduce a catalog-release dependency to finish implementation. ## Open Questions None required to begin implementation. The feature roadmap's policy decisions are settled; the delivery decisions above specify the public shapes and migration path. A newly discovered upstream incompatibility or genuine change of scope should be reported with a recommendation and viable alternative rather than silently changing the accepted configuration boundary or adding restrictions.