Consolidate collection and namespace roadmaps

This commit is contained in:
2026-10-17 05:13:16 +00:00
parent ddda2f8767
commit 683689a4f8
3 changed files with 845 additions and 1079 deletions

View File

@@ -1,541 +0,0 @@
# Proposal 3: Collections With Mounted Configuration Fragments
Status: selected configuration direction; not implemented in PromptKit. Required
ConfigKit capabilities are implemented on its development branch, reviewed at
`e66c371` on 2026-10-16, but are not in PromptKit's selected v0.7.1 dependency.
The recommended direction uses collection-local mapping keys, one installed
definition per prompt, and an optional flat prompt `version` field. The latest
review agrees on shared source checks using `IfPresent` and a distinct collection
`release_version` field. The six configuration decisions below are accepted;
exact public API shapes remain delivery details. The parent [namespace roadmap](namespaces.md) owns the shared decisions. Unselected
proposals 1 and 2 have been retired; their history and the separately captured
upstream request are recorded below.
## Configuration Simplicity
This development round simplifies configuration authoring and consumption:
- Load prompt, profile, and backend libraries as YAML configuration, removing
mandatory catalog Go-module imports and bundled profiles.
- Remove the unused prompt-version selection scheme and its request API fields.
- Let publishers opt into specification checks by declaring a source-root
`version`, commonly in a collection entry. Neither entries nor individual
fragments must declare it; authors need not add headers to every file.
Prefer conventions and small convenience APIs over mandatory workflows.
Preserve consumer choice over sources, layout, namespaces, and precedence without
adding speculative options or stronger compatibility/provenance guarantees.
## Recommendation
Use ConfigKit's implemented input destinations and relative import destinations.
For example, a collection entry can import its `prompts` directory beneath
`[collections, weatherreporter, prompts]`. Authors write local prompt names and
definitions without repeating either `prompts:` or the namespace in each file.
Use a collection-shaped effective configuration. Each collection contains its
release metadata and ordinary mappings of backends, profiles, and prompts.
PromptKit derives qualified public IDs from the final collection and resource
keys after ConfigKit hands off the resolved configuration.
There is one installed definition per qualified prompt ID. Its optional
`version` field describes that definition; it does not create another identity
or select a merge strategy. This avoids identified record sequences and the
current nested prompt-version mapping.
Placement belongs to ConfigKit. PromptKit must not parse, wrap, or rewrite each
source itself, nor impose duplicate-namespace checks before composition. This
preserves the accepted [configuration boundary](../adr/0001-configuration-boundary.md).
## Reviewed Upstream Capabilities And Adoption Status
The reviewed ConfigKit development checkout is `e66c371`. Its public
configuration contract (`docs/config.md`, sections “Input destinations” and
“Shared source-version checks”) and ADRs 0011–0013 own the upstream behavior.
PromptKit still selects ConfigKit v0.7.1; choose a released dependency containing
these capabilities before implementation. This roadmap does not imply they are
already available through PromptKit or select an upstream release number.
The implemented public surface provides:
- `Input.Destination` for root-relative placement, and YAML import
`destination: [prompts]` for placement relative to the immediate importing
document. Glob matches share the declared destination; nested imports append
to their immediate parent's destination.
- `Options.SourceVersionMode` and `LayeredOptions.SourceVersionMode`, using one
shared `Definition.Version` rule. Enabled modes interpret the rule's path in
each document's source-local coordinates before placement and composition.
- Consumption of accepted non-main specification headers, with the main header
retained and protected at its effective application path.
- `SourceInfo.Destination` and `SourceInfo.VersionCheck` for detached inspection
evidence, alongside existing source locations and resource contexts.
Strict mapping composition, explicit precedence, atomic sequences, and local
sibling inheritance retain their existing rules. ConfigKit owns the complete
load; PromptKit interprets and validates final effective values. No further
ConfigKit extension is required for the initial direction described here.
The new PromptKit schema and runtime indexes remain future work. The existing
[format reference](../formats.md) remains authoritative until adoption.
## Authoring And Assembly
A file such as `weatherreporter/prompts/alerts.yml` would contain:
```yaml
summarize.alerts:
version: "1"
default_profile: provider/brief
messages:
- role: user
content: Summarize the weather alerts.
output:
format: text
validation_mode: none
```
The version may simply be omitted. Another collection can contribute the same
local prompt name, for example `homewatch/prompts/alerts.yml`:
```yaml
summarize.alerts:
default_profile: provider/brief
messages:
- role: user
content: Summarize the household alerts.
output:
format: text
validation_mode: none
```
A provider collection's `profiles/brief.yml` uses the same local-key convention:
```yaml
brief:
backend: provider/default
model: vendor/example-model
temperature: 0.2
```
Its `backends/default.yml` could contain this synthetic, non-live endpoint:
```yaml
default:
endpoint: https://inference.example.invalid/v1
```
A conventional `weatherreporter/collection.yml` entry can declare the shared
specification, optional collection release, and its layout:
```yaml
version: 1
release_version: "2.4.0"
configkit:
imports:
- glob: prompts/*.yml
destination: [prompts]
```
A provider entry can import `profiles/*.yml` at `[profiles]` and
`backends/*.yml` at `[backends]` in the same way. Collection publishers choose
which categories to include. A required glob must match; unused categories can
be omitted or use ConfigKit's existing optional-import behavior. Ordinary
fragments may omit specification headers under the selected `IfPresent` mode.
An entry header is the recommended publishing convention, not a load-time
requirement selectively enforced on entries by this mode.
The application selects each entry, enables its imports, and supplies its
namespace through the public input destination. For example, the following
partial Go snippet uses implemented ConfigKit development-branch APIs:
```go
entry := configkit.Input{
Source: configkit.File("/usr/local/share/collections/weatherreporter/collection.yml"),
Imports: true,
Destination: configkit.Keys("collections", "weatherreporter"),
}
```
For independent peer collections, one `Underlay` group's `Inputs` is a useful
starting point, not a required grouping. Consumers choose precedence and groups.
Configure `LayeredOptions.SourceVersionMode` as `SourceVersionModeIfPresent` and
`Definition.Version.Path` as `configkit.Keys("version")`, with PromptKit's
supported-specification checker. The application main input remains at the
root and declares `version: 1` in the examples below; both the main input and
its declaration are optional. Namespace and source selection require no manifest parsing in PromptKit.
| Selected source | Effective destination |
| --- | --- |
| Application main document | Configuration root |
| `weatherreporter/collection.yml` | `[collections, weatherreporter]` |
| Its `prompts/*.yml` imports | `[collections, weatherreporter, prompts]` |
| Homewatch entry and its prompt imports | `[collections, homewatch]` and `[collections, homewatch, prompts]` |
| Provider entry and its profile/backend imports | `[collections, provider]`, then `[profiles]` or `[backends]` appended |
Directly selected fragments with `Input.Destination` remain possible. Entry
imports are the recommended packaging convention because publishers can describe
their layout. Filenames and directory basenames do not define resource identity;
no implicit directory discovery, namespace inference, or collection installer is
introduced. A small helper should construct inputs from an explicitly selected
source and namespace, without inspecting manifests to compute destinations. `collection.yml`
is a convention, not a required filename. Direct fragments and programmatic
sources remain supported through the source API; no parallel collection loader
or mandatory filesystem layout is introduced.
Use later underlay groups or main for intentional application/operator overrides.
Placement does not establish precedence. Do not also recursively scan files
already selected by entry imports: ConfigKit's repeated-source rules still apply.
The entry's source-root `version` is checked and consumed before its payload
composes. Its `release_version` is retained as ordinary collection metadata.
A prompt's nested optional `version` is also ordinary payload. These are three
distinct concepts; source-root release metadata must no longer use `version`.
The assembled application shape would be equivalent to:
```yaml
version: 1
collections:
weatherreporter:
release_version: "2.4.0"
prompts:
summarize.alerts:
version: "1"
default_profile: provider/brief
messages:
- role: user
content: Summarize the weather alerts.
output:
format: text
validation_mode: none
homewatch:
prompts:
summarize.alerts:
default_profile: provider/brief
messages:
- role: user
content: Summarize the household alerts.
output:
format: text
validation_mode: none
provider:
backends:
default:
endpoint: https://inference.example.invalid/v1
profiles:
brief:
backend: provider/default
model: vendor/example-model
temperature: 0.2
```
This yields `weatherreporter/summarize.alerts` and
`homewatch/summarize.alerts`, plus profile `provider/brief` and backend
`provider/default`. The provider's model string remains `vendor/example-model`;
it is not a PromptKit resource identifier.
One fragment may contain several local definitions. A fragment starting directly
with `messages:` would need a destination that also supplies the local prompt
key. ConfigKit mounting permits such placement, but with source checks enabled
its root `version` would be the specification header, not prompt metadata. Recommend
the local-key mapping above as the standard authoring form: identity travels
with the definition and files may be reorganized without changing it. Filename-derived IDs are not
needed.
## Final Schema And Identity
Recommend `collections` as a mapping of namespace to collection body, containing
optional `release_version` and optional `backends`, `profiles`, and `prompts`
mappings. Collection release labels are descriptive, with no SemVer ordering
or dependency-solving semantics. Metadata is optional: an installed collection
can contain resources without claiming a published release.
Each resource key inside a collection is local. The parent namespace and local
key follow the accepted slash-free component grammar; their public spelling is
exactly `namespace/local-name`. There are no duplicate embedded `id` or
`namespace` fields to reconcile. Dots remain ordinary characters.
To retain unqualified application resources, recommend optional root-level
`backends`, `profiles`, and `prompts` mappings, also keyed by local name and
using the same definition shapes. They produce unqualified public IDs. Under
this proposal, namespaced definitions belong under `collections`, not a second
qualified-key spelling in those root maps. This avoids two configuration paths
producing the same public identity. This representation belongs to the selected
future direction; it does not change today's implemented format.
Stored references such as `default_profile`, profile `backend`, and smoke-test
profile defaults remain exact public references. Nesting does not automatically
qualify a slashless reference or rebind it to caller scope. For example, a
profile in `provider` still declares `backend: provider/default`. Caller-scoped
lookup follows the existing namespace roadmap after final indexes are built.
### One Installed Prompt And Optional Version
The resource's qualified ID is its sole configuration identity. There is no
version-key mapping, implicit `latest`, version ordering, or parallel installed
history. Updating the optional version changes metadata on the same prompt.
An optional prompt version is an opaque string with no SemVer, nonblank, or
normalization requirement. Omission or explicit null means no declared label;
null can clear a lower-layer or inherited label. Quote numeric-looking labels
such as `"1"`. Preserve supplied strings, including empty strings, and distinguish
an absent label in inspection. Do not synthesize a version.
Remove request-side prompt-version fields, version selection, ordering, and
version defaults as part of the breaking change. Do not reinterpret those fields
as exact-match assertions. Execution and inspection resolve the installed prompt
by ID alone. Listings expose one prompt per ID with its optional descriptive
label separately. A label neither controls execution nor proves unchanged content.
## ConfigKit Composition Boundary
Use the implemented upstream contracts without duplicating them in PromptKit.
Input destinations use literal mapping-key segments, independent of filesystem
roots and precedence. Relative import destinations are sequences of strings;
omission and `[]` retain the importing destination. Null, scalar, and non-string
destination members are invalid. No logical path segment means parent traversal
or a reset to the application root.
Source-root import directives remain structural. Imported content contributes at
its resulting destination, while physical import paths and `content_file` bases
remain relative to their declaring sources. `SourceInfo.Destination` records
placement; normal origins and diagnostics retain real source locations. Selected
overlays and explicit CLI overrides remain rooted at the application root.
Mounting preserves source identity, cycle/repetition rules, and load limits.
An absent `NoSource` contributes no payload; an actual empty mapping can
materialize its destination containers without clearing lower contents.
ConfigKit's reserved structural keys continue to apply. PromptKit must not
strip headers, re-key source trees, merge fragments itself, or turn source
inspection into an additional enforcement pass.
### Composition And Overrides
Different collection keys prevent accidental collisions between equal local
resource names. Two sources targeting the same namespace are not automatically
invalid: disjoint mapping contributions combine. Overlapping scalar fields,
message sequences, nulls, and equal release labels conflict within a strict
group. Across deliberate layers they follow ordinary precedence instead.
A higher-layer prompt mapping is a partial override. Changing only its version
does not replace its messages or other settings. Omitting a field retains its
lower value, and an empty mapping does not clear a definition. Publishers and
operators must treat such changes as configuration customization, not as an
atomic installation of another prompt release. Do not introduce source audits
or a version-triggered replacement rule to conceal this distinction.
### Inheritance
Existing sibling inheritance remains useful within each collection's resource
mapping: `extends: brief` can name the local profile `brief`. Prompt versions,
now ordinary optional fields, would inherit and overlay like other fields;
`version: null` explicitly clears an inherited label.
Cross-collection profiles are no longer immediate siblings. Consequently,
`extends: provider/brief` cannot reach that collection under current ConfigKit
inheritance. Use existing local sibling inheritance for this development round;
applications can still select the qualified `provider/brief` profile directly.
Authors needing a customized derivative may publish an expanded definition.
Expansion is a migration option, not a mandatory authoring workflow.
Generic cross-path inheritance remains possible future ConfigKit work if a
concrete consumer need justifies it. It is not a prerequisite of this round.
PromptKit must not add its own inheritance resolver after ConfigKit handoff.
## Specification Versions And Collection Inventory
### Shared Specification Policy
Use one `Definition.Version` policy, with source-local path `version`, for the
candidate PromptKit specification. Initially accept specification text `1` from
string or strict decimal-integer declarations; reject explicit null and other
unsupported declarations through the ConfigKit checker. Accept an absent main
declaration, including an absent main input. Accept additional versions only when PromptKit actually supports their format semantics: accepting
a header does not migrate its payload or independently validate a fragment's
complete schema. The retired proposals were alternatives, not released formats
sharing specification version 1.
Use `SourceVersionModeIfPresent` without adding a PromptKit mode-selection
option in this round. A stricter option can be considered for a demonstrated
consumer need. The upstream modes remain distinct:
| Mode | Implemented behavior | Role in this proposal |
| --- | --- | --- |
| `Default` | Existing main-only effective-path check and protected-path behavior | Not the proposed shared-source policy |
| `IfPresent` | Checks present declarations; skips absent non-main declarations | Initial choice for compact fragments |
| `Required` | Requires declarations on every participating document | Upstream capability; exposing a PromptKit option is deferred |
Participating documents include actual main and underlay inputs, transitive and
glob imports, and the selected overlay. Defaults, synthetic CLI overrides,
resolution output, absent optional imports, and empty groups do not need headers.
Explicit null is present and reaches the checker; malformed selected values
fail ConfigKit's version-type validation. A rejected declaration fails loading
even if a higher layer would supersede that source's payload.
In enabled modes, accepted non-main headers are consumed before composition.
The main declaration remains and is protected at its destination-prefixed path.
PromptKit's recommended main is unmounted, so that protected path is `/version`.
Do not confuse header consumption with permission to override the remaining
protected application field.
`IfPresent` does not require a collection entry header and does not infer a
fragment's compatibility from its entry. A publisher can declare compatibility
in the entry while leaving imported files headerless; the assembled configuration
still undergoes normal validation. A declaration is not a guarantee of future
compatibility or independent schema validation of every imported fragment.
ConfigKit checks the declarations actually present. Requiring headers only on
entry files is not supported by the load-wide mode. Do not emulate it using a preliminary manifest load or validation of
source history. If that stronger guarantee becomes essential, seek an explicit
upstream contract instead.
### Naming And Optional Main Inputs
Reserve source-root `version` for specification declarations throughout the new
format. Use `release_version` for optional collection release labels and retain
nested prompt `version` for the optional installed-prompt label. An old release
file containing only `version: "2.4.0"` can fail the specification check; if its
text happens to be accepted, that field is consumed and lost as release metadata.
Migration must rename it rather than simply enable the new mode.
This reservation affects resource fragments whose local key is literally
`version`: a root mapping with that name is interpreted as a malformed header.
Allow that resource name through a nested resource mapping, for example
`prompts: {version: ...}` in a collection entry. Reserve the header position,
not the public resource name. Existing `configkit` and `extends` structural
reservations also remain applicable; destinations do not bypass them.
An absent header in an actual main document still reaches the checker under
`IfPresent`; `NoSource` invokes the absent-main checker as well. PromptKit's
checker accepts omission in both cases. Consumers may assemble only underlays,
fragments, or programmatic inputs without manufacturing a main document or
header. Do not inject a declaration or report undeclared sources as checked.
Present unsupported declarations still fail; final schema validation still runs.
### Inspection And Effective Collection Inventory
`SourceInfo.VersionCheck` is source evidence, not a generic success flag. A
non-nil record with `Present == false` can describe an omission for which the
checker did not run. Header paths and locations are source-local. Evidence is
detached and does not reread inputs; text is conservatively redacted during
callbacks and on failed loads, and successful final records respect completed
sensitivity classification. These records belong in explicit configuration
inspection, not in ordinary domain validation or collection-release identity.
Derive collection inventory from the final `collections` mapping: namespace
plus optional effective `release_version`, sorted and detached from the captured
engine. Metadata-only and resource-only entries can both appear. Root unqualified
resources do not invent a named collection; resource-based namespace enumeration
remains separate. Exact exported inventory types remain API design work.
An inventory describes effective configuration, not immutable package identity,
historical source ownership, or proof of unchanged published contents. Operator
overrides may change resources while retaining a release label. Engine
construction captures definitions; edits require a replacement engine.
## Retired Alternatives And Upstream Request
The unselected proposals were retired after the identified-record design was
captured for separate upstream consideration. Both original documents remain
available in PromptKit Git history at `b5866dd`:
```sh
git show b5866dd:docs/roadmap/configuration-collections-current-configkit.md
git show b5866dd:docs/roadmap/configuration-collections-identified-records.md
```
Proposal 1 used fully qualified mapping keys and the then-current ConfigKit
composition behavior. Proposal 2 used explicit identity fields in record
sequences and requested identity-based composition and inheritance. Neither is
an active PromptKit implementation option. The selected mounted-mapping design
meets the one-installed-prompt requirement with compact local keys and ordinary
mapping composition.
Proposal 2's generic extension is preserved in the ConfigKit repository as
`docs/roadmap/promptkit-identified-records-feature-request.md`. It requests
explicit record-identity registration, composition and overlay by identity,
record inheritance, deterministic ordering, and coherent inspection. That
request is for upstream evaluation, not an accepted ConfigKit capability or a
prerequisite of this roadmap. The subsequently accepted PromptKit decisions
are recorded below.
## Migration
Migration must choose one installed definition for each former multi-version
prompt, move any retained version into its optional field, and relocate
qualified resource keys into collection/local-key mappings. Update destination
declarations, stored references, inventories, and configuration-inspection paths. Rename collection release metadata to
`release_version`, configure the shared checker and mode, and account for the
source-root header reservation and optional main declarations. Remove obsolete
request-version fields and version-selection logic from consumer examples and
public APIs rather than retaining them as assertions. Preserve provider model
strings and source resource bases. Namespace mounting does not
automatically relocate schema or artifact stores or rewrite references when a
collection is renamed.
Retain the accepted removal of mandatory catalog modules and built-in profiles.
This is a breaking configuration/API change under the
[release policy](../policy/release.md); implementation must include consumer
migration guidance and update current contracts when it lands. The proposal
does not change today's supported configuration or API.
## Delivery And Validation
Select a released ConfigKit dependency containing the reviewed capabilities,
then implement PromptKit's schema, source-selection convenience APIs, and final
configuration adapter. Do not use a committed filesystem replacement as the
release integration. Build qualified runtime indexes after handoff. Collection
installation, remote fetching, implicit discovery, live reload, identity-based
list composition, and dependency solving remain outside this work.
PromptKit acceptance should exercise typed assembly of multiple collections,
relative/nested imports, source-local header checking and consumption, ordinary
release and prompt metadata, unqualified resources, scoped selection, optional
prompt versions, inventory without release metadata, source-relative content,
intentional partial overrides, headerless entries/fragments, omitted main inputs
and headers, and resources named `version` in nested mappings. Verify ID-only
lookup and descriptive labels without version selection or request assertions.
Do not duplicate ConfigKit's generic source validation or enforce domain rules through historical source inspection.
Review verification on 2026-10-16 against ConfigKit `e66c371`: focused public API
and consumer-example tests passed. A temporary typed consumer also passed
combined assembly for two collections with equal local prompt names, nested
relative imports and content-file contexts, optional prompt versions, both
enabled header modes, rejected headers despite upper-layer overrides, and
migration behavior for old release fields. The temporary consumer lives outside
both repositories. An additional offline check assembled this document's YAML
fragments through entry imports and matched the illustrated effective tree;
local links and whitespace checks passed. These checks verify upstream behavior
and the candidate schema, not an implemented PromptKit engine feature.
## Accepted Configuration Decisions
The following decisions settle the six questions previously listed here:
1. **Main declaration:** optional, including for programmatic or underlay-only
construction. Validate supplied declarations without injecting missing ones.
2. **Public mode selection:** use `IfPresent`; defer a stricter PromptKit option
until a consumer need justifies it. No per-file header requirement.
3. **Reserved header naming:** reserve source-root `version`, while allowing a
resource named `version` through a nested resource mapping.
4. **Request versions:** remove request-side version fields and selection
machinery. Retain optional descriptive prompt labels only.
5. **Cross-collection inheritance:** use current ConfigKit inheritance; direct
profile references and authored expansion remain available. Defer a generic
upstream extension without adding a PromptKit resolver.
6. **Consumer API and packaging:** provide a small source/namespace convenience
API; recommend entry files and relative imports without requiring a filename,
layout, main input, or single peer group. Preserve direct fragment loading,
programmatic sources, and consumer-controlled precedence. Inventory reports
effective collections with optional release metadata.
## Remaining Delivery Details
No unresolved configuration-policy decision remains from those six questions.
Implementation still needs to select a released ConfigKit dependency containing
the required capabilities, finalize helper signatures and inventory/optional-label
representations, and provide migration examples. These are delivery details,
not reasons to introduce additional workflows or speculative API options.
Stricter header modes and cross-path inheritance are deferred capabilities, not
implementation prerequisites. Update current contracts when behavior lands;
this roadmap records future work and does not itself implement the feature.

View File

@@ -0,0 +1,845 @@
# Configuration Collections, Namespaces, And Scoped Lookup
Status: accepted feature roadmap; not implemented in PromptKit. This document
consolidates the namespace roadmap and selected collection proposal 3. The
configuration and namespace design decisions are settled; public API details
and staged implementation planning remain delivery work.
## Purpose
Simplify PromptKit configuration by loading independently maintained prompt,
profile, and backend libraries as YAML collections instead of mandatory Go
modules. Remove the unused prompt-version selection scheme. Specification
headers are optional: maintainers can declare compatibility in a collection
entry without adding a declaration to every file.
Consumers can select a namespace once and use local resource names while an
engine contains several collections with overlapping names. For example,
WeatherReporter and Homewatch can each define `summarize.alerts`, while provider
namespaces distinguish profiles targeting the same upstream model.
Conventions and small convenience APIs should reduce authoring and maintenance
work. Preserve consumer choice over sources, layouts, namespaces, and precedence
without adding speculative options, mandatory workflows, or new compatibility
and provenance guarantees.
## Prerequisite: Adopt ConfigKit v0.8.0
Adopt released ConfigKit **v0.8.0** before implementing the new collection schema
and loading APIs. PromptKit currently selects v0.7.1. Update the module dependency
and checksums, review affected public API compatibility and attribution, and
verify the existing ConfigKit integration as the prerequisite implementation
unit. Do not use a committed local filesystem replacement for adoption.
The v0.8.0 tag was reviewed at `137769f` on 2026-10-17. It supplies input
placement, relative import destinations, and shared source-version checks needed
by this design. No additional upstream extension is required. Recording this
prerequisite does not itself upgrade PromptKit's dependency.
ConfigKit's public `docs/config.md`, ADRs 0011–0014, and v0.8.0 release notes own
the upstream contracts. The capabilities used here are:
- `Input.Destination` for root-relative placement and import `destination` for
placement relative to the immediate importing document.
- `Options.SourceVersionMode` and `LayeredOptions.SourceVersionMode`, applying
a shared `Definition.Version` policy in each document's source-local coordinates.
- Consumption of accepted non-main headers before composition, with the main
header retained and protected at its effective application path.
- Detached `SourceInfo.Destination` and `SourceInfo.VersionCheck` evidence,
together with existing source locations and resource contexts.
### Keep Mapping-Based Collections
ConfigKit v0.8.0 also offers sequence-item placement and registered composition
of distinct list records. These were reviewed and are not selected for this
round. A higher-priority list replaces the entire lower-priority list, duplicate
identities conflict within a strict group, and records cannot inherit from
sibling list records. Switching formats would sacrifice ordinary per-resource
partial overrides and local inheritance for flatter authoring.
Keep collection resources as mappings keyed by local ID. Do not add an
alternative list schema or a PromptKit identity-based merge layer. The existing
key supplies identity without an additional embedded `id`. This is a scope
choice for this round, not a prohibition on future upstream capabilities.
## Existing Foundation And Ownership
The [format reference](../formats.md) and
[consumer guide](../consumers/pkg-promptkit.md) remain authoritative for current
behavior until implementation lands. Directory and embedded configuration
loading already exist through `DirectoryInputs` and `FilesystemInputs`.
The current engine also supplies provider catalog modules and built-in profiles;
the accepted removal is described below.
[ADR 0001](../adr/0001-configuration-boundary.md) assigns source loading,
composition, and inheritance to ConfigKit. PromptKit interprets and validates
only final effective values, including their resource contexts. Source history
is available for explicit inspection, not additional validation of contributions.
Do not add a manifest pre-parser, source-level namespace ownership checks, or a
second composition pass. Two sources targeting the same namespace follow
ordinary ConfigKit composition; a repeated namespace is not a separate error.
The [architecture policy](../policy/architecture.md) continues to assign CLI
syntax, discovery policy, and application lifecycle to consuming applications.
## Collection Ownership And Built-In Removal
**Accepted: load collections as application/operator-supplied configuration,
and remove PromptKit's built-in profiles as a breaking change.** Remove the
mandatory OpenRouter and RakestrawHome catalog Go-module dependencies and their
automatic contribution to engine configuration. PromptKit owns the definition
format and execution machinery; collection publishers own their configuration
repositories, and applications/operators select and provision the collections
they use. One or more explicitly selected directories can supply backends,
profiles, and prompts through the existing ConfigKit integration.
Remove `promptkit-openrouter-standard` and `promptkit-openrouter-auto`, including
their implicit catalog dependencies. Do not replace them with another mandatory
starter bundle. Applications may embed their own defaults using the same
configuration format and loader, then layer operator configuration as desired.
Ordinary application overrides remain valid configuration and need not declare
a collection release of their own.
This decouples collection updates from PromptKit rebuilds and releases and
avoids imposing provider inventories on every consumer. The tradeoff is that
applications and deployments must supply their required configuration and
manage compatible collection revisions. PromptKit does not gain a collection
installer, automatic downloader, or implicit directory search policy.
Retain the captured-engine lifecycle: configuration changes take effect when
the application constructs and validates a replacement engine. A change to an
installed directory does not mutate an existing engine's captured definitions.
Distribution as configuration does not make new provider protocols or diagnostic
adapters data-only features; those can still require implementation work.
Prepare explicit identifier mappings, replacement configuration examples, and
consumer migration instructions. Update the built-in-profile promise in the
release policy and its canonical format documentation when removal lands.
Use a release permitted to break configuration and API contracts under the
current release policy: a minor release before v1, or a major release at/after
v1. Actual catalog mappings, packaging arrangements, and release versions remain
delivery work; independent collection releases need not track future PromptKit
software releases.
## Accepted Identity Convention
Reserve `/` exclusively as the namespace separator in PromptKit prompt, profile,
and backend identifiers and references. A qualified identifier has exactly two
nonempty components: `namespace/local-name`. Neither component can contain `/`.
Dots remain available within local names. An unqualified identifier has no slash
and remains valid under the existing nonblank-ID rule.
Reject resource identifiers or supplied references with multiple slashes or an
empty qualified component, such as `a/b/c`, `/name`, and `namespace/`. These
rules do not apply to provider model values, endpoints, resource paths, or prompt
versions. Preserve exact spelling; do not silently trim or rewrite IDs.
| Resource | Namespace | Local name | Qualified ID |
| --- | --- | --- | --- |
| Prompt | `weatherreporter` | `summarize.alerts` | `weatherreporter/summarize.alerts` |
| Prompt | `homewatch` | `summarize.alerts` | `homewatch/summarize.alerts` |
| Profile | `openrouter` | `google.gemma-4-31b-it` | `openrouter/google.gemma-4-31b-it` |
| Profile | `rakestrawhome` | `google.gemma-4-31b-it` | `rakestrawhome/google.gemma-4-31b-it` |
Prompt, profile, and backend identities remain separate resource types. The
same namespace can contain all three, and resources in it may come from
multiple configuration sources. A namespace does not imply a directory,
package, provider model identifier, or security boundary.
A profile ID identifies execution settings. Its configured model value is
still the identifier passed to the provider; qualifying the profile ID does
not modify that value. Both example profiles may retain the configured model
`google/gemma-4-31b-it`. Different profiles may select the same model with
different settings. Prompt version labels remain separate from namespaces. The
selected collection format installs one definition per prompt ID and removes
request-side version selection and assertions. Optional labels are descriptive.
Retain unqualified and dotted IDs. Existing slash-containing IDs need review:
those with one slash and nonempty components become qualified identities, while
those outside the new grammar require migration. This intentional format break
is accepted in favor of unambiguous resolution; the migration work is described
below.
## Accepted Consumer Scope
Provide a lightweight, immutable view over an existing engine with independent
prompt, profile, and backend scopes. The following sketch illustrates the
accepted shape; method/type names and final signatures remain provisional:
```go
weather, err := engine.WithNamespaces(Namespaces{
Prompt: "weatherreporter",
Profile: "openrouter",
})
// Handle err, then use local prompt and profile names through weather.
```
These declarations do not exist yet. Empty scope fields mean no scope for that
resource type. Keep name qualification shared across the view and engine; do not
duplicate selection logic in each operation. Initially omit a one-string shorthand
that implicitly scopes all resource types.
The view would share the engine's captured configuration, clients, and execution
machinery. Selecting a namespace would not rebuild the engine or duplicate its
backend capacity accounting. Consumers could use different views concurrently
without changing a shared current-namespace setting.
The accepted resolution rules, independent of the final scope API, are:
1. A supplied name without a slash is qualified using the selected scope for its
resource type, then looked up exactly. Without that scope, it is looked up as
an exact unqualified ID.
2. A missing scoped resource does not trigger a search in other namespaces or
among unqualified IDs. Loading another collection cannot redirect lookup.
3. A valid supplied name containing one slash is fully qualified and is looked
up exactly, regardless of scope. Malformed resource references are rejected.
4. Scope applies to caller-supplied resource names. Stored references, including
prompt default profiles, profile backends, inheritance references, and backend
smoke-test default profiles, retain their existing exact meaning. They are
not rebound to the invoking consumer's namespace.
5. Omitted optional IDs retain their existing selection/default behavior; an
omission is not converted into a namespace prefix or a lookup for an empty
local name.
6. Where outputs, inspection, errors, or diagnostic reports identify a selected
resource, preserve its resolved full identity. Any exposed local name should
be distinguishable from that identity.
Keep qualification consistent across execution, preparation, request validation,
prompt/profile inspection, and applicable smoke-test selections. Namespace
selection must not change request override precedence or provider model strings.
Prompts resolve by ID alone.
### Local And Qualified References In One Operation
Syntax alone distinguishes local and qualified references. Do not decide whether
to qualify a name by checking which candidates exist; that would make resolution
depend on loaded content.
Within a `weatherreporter` prompt scope, `summarize.alerts` resolves only to
`weatherreporter/summarize.alerts`, while `homewatch/summarize.alerts` explicitly
selects that other library's prompt. A qualified profile override similarly
bypasses the profile scope. Scoped operations accept both forms without a
separate reference type or requiring a return to the original engine for
cross-namespace access.
The original engine remains a way to select an exact unqualified ID without
applying a scope. No escape syntax for unqualified IDs is introduced here.
### Separate Resource Scopes
A consumer can select prompt shorthand under `weatherreporter` and profile
shorthand under `openrouter` in the same request. Each resource type has an
independent scope.
A prompt's configured default profile needs no caller profile scope because
the stored reference is already exact. Scope syntax and existence handling are
defined in [scope validation](#scope-validation).
### Scope Validation
**Accepted: validate syntax when creating the view; resolve existence when
an operation selects a resource.** In the scope value, the empty
string means no scope. Reject a nonempty namespace containing `/` or consisting
only of whitespace. Otherwise preserve its exact spelling, with no trimming,
case folding, or additional character whitelist. This distinguishes omission
from an unusable namespace without inventing normalization rules. Report invalid
scope construction through PromptKit's existing public error conventions.
Allow a well-formed namespace even when it has no current members. Its scoped
listing would be empty, and selection of a missing local resource would produce
the ordinary lookup error. Qualified selections would remain usable regardless
of the view's default scope. An empty optional request ID continues to mean
omission under that operation's existing contract; it is never qualified.
This keeps scope as a naming context and supports uniform application setup
across installations with different library contents. It also avoids treating
successful scope construction as validation of a prompt or execution profile.
The tradeoff is that a misspelled but syntactically valid namespace is detected
only when listed or used, rather than during view construction.
## Discovery And Namespace Filtering
**Accepted: integrated namespace filtering and full-identity results.**
Enumerate the distinct named namespaces present in final effective
prompts, profiles, and backends. Allow filtering that enumeration by resource
type so a prompt picker need not show profile-only namespaces. Provide scoped
listings for the supported resource types, adding a backend inventory surface
as part of this work if needed. Namespace filtering is an explicit option in
the library listing API, not a consumer-side filtering helper. Preserve unfiltered
engine listing behavior, with the accepted removal of prompt-version identity
and selection; the exact Go option shape remains to be specified.
| Selection | Listing behavior |
| --- | --- |
| No explicit filter on the engine | All namespaces, including unqualified resources |
| No explicit filter on a scoped view | The selected scope for that resource type; all resources of that type if no scope is selected |
| Explicit named namespace | Resources in exactly that namespace |
| Explicit unqualified-only filter | Resources whose IDs have no namespace |
| Explicit all-namespaces filter | All resources of that type, including unqualified resources |
An explicit filter replaces the view's default for the current listing; it
does not intersect with that default or mutate the view. A named namespace
filter uses the namespace syntax rules above. A well-formed namespace
with no matching resources returns an empty listing. Represent default, named,
unqualified-only, and all-namespaces selections distinctly in the API; do not
overload an empty string to mean several of them.
Return full IDs with optional prompt version labels separately; the full ID
identifies the installed prompt. Do not invent a named namespace such as `default`
for unqualified resources. Namespace enumeration excludes that unnamed group.
Use deterministic ordering consistent with existing listing contracts.
Qualified result IDs can be passed unchanged to either scoped or unscoped
operations. Unqualified IDs remain literal unqualified identities: when an
explicit all-namespaces or unqualified-only filter exposes one through a scoped
view, use the original engine or a view without that resource scope to select
it exactly. A listing filter does not change subsequent execution scope. This
preserves the accepted lookup rules without introducing an escape syntax.
Integrated filtering gives consumers a direct way to discover the desired
resources, while full identities keep logs and subsequent selections
unambiguous. Namespace/local-name display decomposition is separate from
filtering; a public splitting helper is not required by this decision.
Namespace membership is exact: `weather` does not include `weatherreporter`.
Collection inventory describes final collection declarations and optional release
labels; it is distinct from enumeration of namespaces that contain resources.
See [collection inventory](#inspection-and-effective-collection-inventory).
## Authoring And Assembly
A file such as `weatherreporter/prompts/alerts.yml` would contain:
```yaml
summarize.alerts:
version: "1"
default_profile: provider/brief
messages:
- role: user
content: Summarize the weather alerts.
output:
format: text
validation_mode: none
```
The version may simply be omitted. Another collection can contribute the same
local prompt name, for example `homewatch/prompts/alerts.yml`:
```yaml
summarize.alerts:
default_profile: provider/brief
messages:
- role: user
content: Summarize the household alerts.
output:
format: text
validation_mode: none
```
A provider collection's `profiles/brief.yml` uses the same local-key convention:
```yaml
brief:
backend: provider/default
model: vendor/example-model
temperature: 0.2
```
Its `backends/default.yml` could contain this synthetic, non-live endpoint:
```yaml
default:
endpoint: https://inference.example.invalid/v1
```
A conventional `weatherreporter/collection.yml` entry can declare the shared
specification, optional collection release, and its layout:
```yaml
version: 1
release_version: "2.4.0"
configkit:
imports:
- glob: prompts/*.yml
destination: [prompts]
```
A provider entry can import `profiles/*.yml` at `[profiles]` and
`backends/*.yml` at `[backends]` in the same way. Collection publishers choose
which categories to include. A required glob must match; unused categories can
be omitted or use ConfigKit's existing optional-import behavior. Ordinary
fragments may omit specification headers under the selected `IfPresent` mode.
An entry header is the recommended publishing convention, not a load-time
requirement selectively enforced on entries by this mode.
The application selects each entry, enables its imports, and supplies its
namespace through the public input destination. For example, the following
partial Go snippet uses released ConfigKit v0.8.0 APIs:
```go
entry := configkit.Input{
Source: configkit.File("/usr/local/share/collections/weatherreporter/collection.yml"),
Imports: true,
Destination: configkit.Keys("collections", "weatherreporter"),
}
```
For independent peer collections, one `Underlay` group's `Inputs` is a useful
starting point, not a required grouping. Consumers choose precedence and groups.
Configure `LayeredOptions.SourceVersionMode` as `SourceVersionModeIfPresent` and
`Definition.Version.Path` as `configkit.Keys("version")`, with PromptKit's
supported-specification checker. The application main input remains at the
root and declares `version: 1` in the examples below; both the main input and
its declaration are optional. Namespace and source selection require no manifest parsing in PromptKit.
| Selected source | Effective destination |
| --- | --- |
| Application main document | Configuration root |
| `weatherreporter/collection.yml` | `[collections, weatherreporter]` |
| Its `prompts/*.yml` imports | `[collections, weatherreporter, prompts]` |
| Homewatch entry and its prompt imports | `[collections, homewatch]` and `[collections, homewatch, prompts]` |
| Provider entry and its profile/backend imports | `[collections, provider]`, then `[profiles]` or `[backends]` appended |
Directly selected fragments with `Input.Destination` remain possible. Entry
imports are the recommended packaging convention because publishers can describe
their layout. Filenames and directory basenames do not define resource identity;
no implicit directory discovery, namespace inference, or collection installer is
introduced. A small helper should construct inputs from an explicitly selected
source and namespace, without inspecting manifests to compute destinations. `collection.yml`
is a convention, not a required filename. Direct fragments and programmatic
sources remain supported through the source API; no parallel collection loader
or mandatory filesystem layout is introduced.
Use later underlay groups or main for intentional application/operator overrides.
Placement does not establish precedence. Do not also recursively scan files
already selected by entry imports: ConfigKit's repeated-source rules still apply.
The entry's source-root `version` is checked and consumed before its payload
composes. Its `release_version` is retained as ordinary collection metadata.
A prompt's nested optional `version` is also ordinary payload. These are three
distinct concepts; source-root release metadata must no longer use `version`.
The assembled application shape would be equivalent to:
```yaml
version: 1
collections:
weatherreporter:
release_version: "2.4.0"
prompts:
summarize.alerts:
version: "1"
default_profile: provider/brief
messages:
- role: user
content: Summarize the weather alerts.
output:
format: text
validation_mode: none
homewatch:
prompts:
summarize.alerts:
default_profile: provider/brief
messages:
- role: user
content: Summarize the household alerts.
output:
format: text
validation_mode: none
provider:
backends:
default:
endpoint: https://inference.example.invalid/v1
profiles:
brief:
backend: provider/default
model: vendor/example-model
temperature: 0.2
```
This yields `weatherreporter/summarize.alerts` and
`homewatch/summarize.alerts`, plus profile `provider/brief` and backend
`provider/default`. The provider's model string remains `vendor/example-model`;
it is not a PromptKit resource identifier.
One fragment may contain several local definitions. A fragment starting directly
with `messages:` would need a destination that also supplies the local prompt
key. ConfigKit mounting permits such placement, but with source checks enabled
its root `version` would be the specification header, not prompt metadata. Recommend
the local-key mapping above as the standard authoring form: identity travels
with the definition and files may be reorganized without changing it. Filename-derived IDs are not
needed.
## Final Schema And Identity
Use `collections` as a mapping of namespace to collection body, containing
optional `release_version` and optional `backends`, `profiles`, and `prompts`
mappings. Collection release labels are descriptive, with no SemVer ordering
or dependency-solving semantics. Metadata is optional: an installed collection
can contain resources without claiming a published release.
Each resource key inside a collection is local. The parent namespace and local
key follow the accepted slash-free component grammar; their public spelling is
exactly `namespace/local-name`. There are no duplicate embedded `id` or
`namespace` fields to reconcile. Dots remain ordinary characters.
Retain unqualified application resources through optional root-level
`backends`, `profiles`, and `prompts` mappings, also keyed by local name and
using the same definition shapes. They produce unqualified public IDs. Under
this proposal, namespaced definitions belong under `collections`, not a second
qualified-key spelling in those root maps. This avoids two configuration paths
producing the same public identity. This representation belongs to the selected
future direction; it does not change today's implemented format.
Stored references such as `default_profile`, profile `backend`, and smoke-test
profile defaults remain exact public references. Nesting does not automatically
qualify a slashless reference or rebind it to caller scope. For example, a
profile in `provider` still declares `backend: provider/default`. Caller-scoped
lookup follows [the scope rules above](#accepted-consumer-scope) after final
indexes are built.
### One Installed Prompt And Optional Version
The resource's qualified ID is its sole configuration identity. There is no
version-key mapping, implicit `latest`, version ordering, or parallel installed
history. Updating the optional version changes metadata on the same prompt.
An optional prompt version is an opaque string with no SemVer, nonblank, or
normalization requirement. Omission or explicit null means no declared label;
null can clear a lower-layer or inherited label. Quote numeric-looking labels
such as `"1"`. Preserve supplied strings, including empty strings, and distinguish
an absent label in inspection. Do not synthesize a version.
Remove request-side prompt-version fields, version selection, ordering, and
version defaults as part of the breaking change. Do not reinterpret those fields
as exact-match assertions. Execution and inspection resolve the installed prompt
by ID alone. Listings expose one prompt per ID with its optional descriptive
label separately. A label neither controls execution nor proves unchanged content.
## ConfigKit Composition Boundary
Use the implemented upstream contracts without duplicating them in PromptKit.
Input destinations use literal mapping-key segments, independent of filesystem
roots and precedence. Relative import destinations are sequences of strings;
omission and `[]` retain the importing destination. Null, scalar, and non-string
destination members are invalid. No logical path segment means parent traversal
or a reset to the application root.
Source-root import directives remain structural. Imported content contributes at
its resulting destination, while physical import paths and `content_file` bases
remain relative to their declaring sources. `SourceInfo.Destination` records
placement; normal origins and diagnostics retain real source locations. Selected
overlays and explicit CLI overrides remain rooted at the application root.
Mounting preserves source identity, cycle/repetition rules, and load limits.
An absent `NoSource` contributes no payload; an actual empty mapping can
materialize its destination containers without clearing lower contents.
ConfigKit's reserved structural keys continue to apply. PromptKit must not
strip headers, re-key source trees, merge fragments itself, or turn source
inspection into an additional enforcement pass.
### Composition And Overrides
Different collection keys prevent accidental collisions between equal local
resource names. Two sources targeting the same namespace are not automatically
invalid: disjoint mapping contributions combine. Overlapping scalar fields,
message sequences, nulls, and equal release labels conflict within a strict
group. Across deliberate layers they follow ordinary precedence instead.
A higher-layer prompt mapping is a partial override. Changing only its version
does not replace its messages or other settings. Omitting a field retains its
lower value, and an empty mapping does not clear a definition. Publishers and
operators must treat such changes as configuration customization, not as an
atomic installation of another prompt release. Do not introduce source audits
or a version-triggered replacement rule to conceal this distinction.
### Inheritance
Existing sibling inheritance remains useful within each collection's resource
mapping: `extends: brief` can name the local profile `brief`. Prompt versions,
now ordinary optional fields, would inherit and overlay like other fields;
`version: null` explicitly clears an inherited label.
Cross-collection profiles are no longer immediate siblings. Consequently,
`extends: provider/brief` cannot reach that collection under current ConfigKit
inheritance. Use existing local sibling inheritance for this development round;
applications can still select the qualified `provider/brief` profile directly.
Authors needing a customized derivative may publish an expanded definition.
Expansion is a migration option, not a mandatory authoring workflow.
Generic cross-path inheritance remains possible future ConfigKit work if a
concrete consumer need justifies it. It is not a prerequisite of this round.
PromptKit must not add its own inheritance resolver after ConfigKit handoff.
## Specification Versions And Collection Inventory
### Shared Specification Policy
Use one `Definition.Version` policy, with source-local path `version`, for the
candidate PromptKit specification. Initially accept specification text `1` from
string or strict decimal-integer declarations; reject explicit null and other
unsupported declarations through the ConfigKit checker. Accept an absent main
declaration, including an absent main input. Accept additional versions only
when PromptKit actually supports their format semantics: accepting
a header does not migrate its payload or independently validate a fragment's
complete schema. The retired proposals were alternatives, not released formats
sharing specification version 1.
Use `SourceVersionModeIfPresent` without adding a PromptKit mode-selection
option in this round. A stricter option can be considered for a demonstrated
consumer need. The upstream modes remain distinct:
| Mode | Implemented behavior | Role in this proposal |
| --- | --- | --- |
| `Default` | Existing main-only effective-path check and protected-path behavior | Not the proposed shared-source policy |
| `IfPresent` | Checks present declarations; skips absent non-main declarations | Initial choice for compact fragments |
| `Required` | Requires declarations on every participating document | Upstream capability; exposing a PromptKit option is deferred |
Participating documents include actual main and underlay inputs, transitive and
glob imports, and the selected overlay. Defaults, synthetic CLI overrides,
resolution output, absent optional imports, and empty groups do not need headers.
Explicit null is present and reaches the checker; malformed selected values
fail ConfigKit's version-type validation. A rejected declaration fails loading
even if a higher layer would supersede that source's payload.
In enabled modes, accepted non-main headers are consumed before composition.
The main declaration remains and is protected at its destination-prefixed path.
PromptKit's recommended main is unmounted, so that protected path is `/version`.
Do not confuse header consumption with permission to override the remaining
protected application field.
`IfPresent` does not require a collection entry header and does not infer a
fragment's compatibility from its entry. A publisher can declare compatibility
in the entry while leaving imported files headerless; the assembled configuration
still undergoes normal validation. A declaration is not a guarantee of future
compatibility or independent schema validation of every imported fragment.
ConfigKit checks the declarations actually present. Requiring headers only on
entry files is not supported by the load-wide mode. Do not emulate it using a
preliminary manifest load or validation of
source history. If that stronger guarantee becomes essential, seek an explicit
upstream contract instead.
### Naming And Optional Main Inputs
Reserve source-root `version` for specification declarations throughout the new
format. Use `release_version` for optional collection release labels and retain
nested prompt `version` for the optional installed-prompt label. An old release
file containing only `version: "2.4.0"` can fail the specification check; if its
text happens to be accepted, that field is consumed and lost as release metadata.
Migration must rename it rather than simply enable the new mode.
This reservation affects resource fragments whose local key is literally
`version`: a root mapping with that name is interpreted as a malformed header.
Allow that resource name through a nested resource mapping, for example
`prompts: {version: ...}` in a collection entry. Reserve the header position,
not the public resource name. Existing `configkit` and `extends` structural
reservations also remain applicable; destinations do not bypass them.
An absent header in an actual main document still reaches the checker under
`IfPresent`; `NoSource` invokes the absent-main checker as well. PromptKit's
checker accepts omission in both cases. Consumers may assemble only underlays,
fragments, or programmatic inputs without manufacturing a main document or
header. Do not inject a declaration or report undeclared sources as checked.
Present unsupported declarations still fail; final schema validation still runs.
### Inspection And Effective Collection Inventory
`SourceInfo.VersionCheck` is source evidence, not a generic success flag. A
non-nil record with `Present == false` can describe an omission for which the
checker did not run. Header paths and locations are source-local. Evidence is
detached and does not reread inputs; text is conservatively redacted during
callbacks and on failed loads, and successful final records respect completed
sensitivity classification. These records belong in explicit configuration
inspection, not in ordinary domain validation or collection-release identity.
Derive collection inventory from the final `collections` mapping: namespace
plus optional effective `release_version`, sorted and detached from the captured
engine. Metadata-only and resource-only entries can both appear. Root unqualified
resources do not invent a named collection; resource-based namespace enumeration
remains separate. Exact exported inventory types remain API design work.
An inventory describes effective configuration, not immutable package identity,
historical source ownership, or proof of unchanged published contents. Operator
overrides may change resources while retaining a release label. Engine
construction captures definitions; edits require a replacement engine.
## Migration
Migration must choose one installed definition for each former multi-version
prompt, move any retained version into its optional field, and relocate
qualified resource keys into collection/local-key mappings. Update destination
declarations, stored references, inventories, and configuration-inspection paths.
Rename collection release metadata to
`release_version`, configure the shared checker and mode, and account for the
source-root header reservation and optional main declarations. Remove obsolete
request-version fields and version-selection logic from consumer examples and
public APIs rather than retaining them as assertions. Preserve provider model
strings and source resource bases. Namespace mounting does not
automatically relocate schema or artifact stores or rewrite references when a
collection is renamed.
Retain the accepted removal of mandatory catalog modules and built-in profiles.
This is a breaking configuration/API change under the
[release policy](../policy/release.md); implementation must include consumer
migration guidance and update current contracts when it lands. The proposal
does not change today's supported configuration or API.
Existing unscoped exact lookup remains available for IDs valid under the new
grammar. Compatibility with arbitrary slash-containing resource IDs is
intentionally broken. The migration must:
- Audit maintained catalogs and representative consumer definitions for invalid
IDs and for valid one-slash IDs whose namespace meaning needs review.
- Choose explicit old-to-new mappings and check for collisions. Do not
automatically replace slashes with dots: distinct existing IDs could collapse
to the same new identity.
- Update renamed keys and their references together, including inheritance,
prompt default profiles, profile backend references, backend smoke-test
defaults, and affected examples and consumer request IDs.
- Keep provider model strings unchanged. Renaming a profile does not rename
the upstream model.
- Document consumer action and coordinate the PromptKit format change with
catalog adoption under the [release policy](../policy/release.md). Its catalog
profile-data exception does not cover this general format/API behavior change;
deliberately retire its built-in-profile preservation promise when the
accepted removal lands. Current policy and format documents remain unchanged
until implementation.
Renaming a backend changes its identity; duplicating it under another ID can
separate capacity accounting. Do not use blanket aliases or duplicate catalog
entries as an automatic compatibility mechanism. Exact release versions and
catalog mappings remain implementation-planning work.
## Work Deferred Or Outside This Round
- Collection installation, automatic downloading, implicit directory discovery,
package registries, dependency solving, and live reload.
- Automatic rewriting of stored references when mounting or renaming collections.
- Implicit namespace search paths, fallback lookup, namespace-based access control,
and filesystem isolation.
- Changes to provider model names, inference behavior, or ConfigKit precedence.
- Sequence-item resource catalogs, identity-based overlays, cross-path inheritance,
and a PromptKit option requiring specification headers in every document.
Explicit source destinations, direct fragments, programmatic sources, and
consumer-selected precedence remain supported in the design. Deferred features
can be reconsidered for concrete needs; none blocks implementation.
## Delivery And Validation
The next work is a staged implementation plan grounded in these accepted
contracts. Its first prerequisite is [ConfigKit v0.8.0 adoption](#prerequisite-adopt-configkit-v080).
Then cover the collection schema and final configuration adapter, catalog and
built-in removal, prompt-version API removal, immutable scoped views, integrated
filtering, and collection inventory. Build qualified runtime indexes after
ConfigKit handoff. Select exact helper signatures, listing options, and metadata
representations using representative consumer examples.
Plan focused offline validation under the [testing policy](../policy/testing.md).
Update GoDoc, the format reference, consumer guidance, affected release policy,
and internal documentation when behavior lands. Retire this roadmap after the
work is complete. This outline is not yet the staged implementation plan.
### Namespace And Consumer Acceptance
- Two prompt scopes resolve the same local name to their respective prompts;
a missing name never resolves from the other scope or an unqualified entry.
- Two provider profile scopes resolve the same local name, such as
`google.gemma-4-31b-it`, to different profiles without changing the configured
provider model value `google/gemma-4-31b-it`.
- A qualified reference bypasses the selected scope without double qualification;
adding another collection does not change local or qualified resolution.
- Multiple slashes and empty qualified components are rejected in resource IDs
and references, while provider model values retain their existing syntax.
- Prompt shorthand and a profile override use their intended scopes, while
stored default references and omitted selections retain their meaning.
- Scoped views coexist concurrently and share backend capacity with ordinary
calls on the underlying engine.
- Scope creation rejects invalid syntax, accepts well-formed absent namespaces,
and treats empty scope fields as no scope. Missing resources fail at lookup;
qualified references remain usable even when the default namespace is absent.
- Listing without an explicit filter uses the resource's view scope, or lists
all resources when no scope is selected. Explicit named, unqualified-only,
and all-namespaces filters override that default for the current listing only.
- A valid namespace with no matches produces an empty listing. Namespace
filtering respects resource type and exact namespace boundaries.
- Exact-ID calls using valid IDs and intentional overlays retain their behavior.
Migrated catalog references resolve without collisions; migration installs one
prompt per ID with an optional descriptive label.
- Listings preserve full IDs and separate optional prompt version labels.
Qualified results round-trip through either engine or view; unqualified results
round-trip through the engine without a corresponding scope.
- Representative validation, inspection, execution, and smoke-test paths use
the same qualification rules without duplicating every test at every layer.
- Engines use caller-selected definitions without automatically contributing
provider catalogs or PromptKit-owned profiles. Ordinary directory and embedded
configuration sources retain ConfigKit composition semantics.
- PromptKit does not add source-history-based duplicate-namespace rejection or
independently pre-validate collection definitions before the final handoff.
### Configuration Acceptance
Exercise typed assembly of multiple collections, relative/nested imports,
source-local header checking and consumption, ordinary release and prompt
metadata, unqualified resources, optional prompt labels, inventory without
release metadata, source-relative content, and intentional partial overrides.
Cover headerless entries/fragments, omitted main inputs and headers, and
resources named `version` in nested mappings. Verify ID-only lookup without
request-version selection or assertions. No automatic provider catalogs or
built-in profiles should be contributed.
Do not duplicate ConfigKit's generic source validation or enforce domain rules
through historical source inspection. Preserve local inheritance and ordinary
mapping overrides while migrating catalog definitions.
### Review Evidence
The 2026-10-16 review against ConfigKit development commit `e66c371` verified
mounted assembly, relative imports and resource contexts, shared header checks,
and this document's YAML assembly through public consumer tests. The 2026-10-17
review of release v0.8.0 at `137769f` passed maintained consumer examples and
focused public API probes for sequence assembly, duplicate rejection, whole-list
replacement, inheritance limits, header consumption, and final identity validation
boundaries. The latter review informed the decision to retain mappings. These
checks establish upstream behavior, not an implemented PromptKit feature.
## Remaining Delivery Details
No substantive design question remains before staged implementation planning.
ConfigKit v0.8.0 is the selected prerequisite, not an unresolved release choice.
Finalize public helper signatures, inventory and optional-label representations,
identifier migration mappings, and concrete consumer migration examples in the
plan and implementation. Do not reopen settled workflows or add speculative
options merely to complete API shapes.
## Consolidation And Retired Alternatives
This document replaces the separate namespace roadmap and collection proposal 3.
Their pre-consolidation versions, including considered namespace API alternatives,
remain available at PromptKit commit `ddda2f8`:
```sh
git show ddda2f8:docs/roadmap/namespaces.md
git show ddda2f8:docs/roadmap/configuration-collections-mounted-fragments.md
```
The unselected collection proposals remain available at `b5866dd`:
```sh
git show b5866dd:docs/roadmap/configuration-collections-current-configkit.md
git show b5866dd:docs/roadmap/configuration-collections-identified-records.md
```
Proposal 1 used fully qualified mapping keys. Proposal 2 requested identified
record sequences, identity-based overlays, and record inheritance. ConfigKit
v0.8.0 implements a narrower sequence-composition capability; it does not supply
those identity-based overlays or inheritance. Its sequence feature was evaluated
and not selected for this roadmap. The original upstream feature-request lineage
is recorded in ConfigKit history under
`docs/roadmap/promptkit-identified-records-feature-request.md`; no outstanding
part of that request is a prerequisite here.
The accepted configuration choices remain: optional main declarations and
if-present checks; source-root `version` reserved without banning that resource
name; removal of request-version machinery; current ConfigKit inheritance; and
flexible source assembly with a small convenience API. This consolidation does
not change those decisions or implement the feature.

View File

@@ -1,538 +0,0 @@
# Namespaces, Collections, And Scoped Resource Lookup
Status: feature roadmap; not implemented. The reserved-slash naming convention,
reference-resolution rules, decisions 1–3 (scope shape, validation, and integrated
discovery filtering), and decision 4's move to application/operator-supplied
configuration are accepted target behavior. Decision 5 selects mounted collections
and optional source-version checking. Its six configuration decisions are
accepted in the collection roadmap, subject to the ConfigKit boundary. Exact Go
names and option types remain delivery details.
## Purpose
Simplifying configuration is a primary goal of this round: YAML collections
replace mandatory catalog Go-module imports, unused prompt-version selection is
removed, and specification declarations are optional. Publishers may declare a
specification in an entry document without adding headers to every file.
Conventions should ease authoring without prescribing consumer layout or
precedence. The [collection roadmap](configuration-collections-mounted-fragments.md)
owns the configuration decisions and delivery details.
Let consumers select a namespace once and use convenient local names within
that namespace across PromptKit operations. An assembled engine may contain
multiple application prompt libraries and provider profile catalogs with
overlapping local names. Resolution must remain unambiguous.
The motivating cases are:
- WeatherReporter and another application both define `summarize.alerts`.
Each consumer selects its application namespace and uses the local name.
- OpenRouter and RakestrawHome both provide the model identified in the
discussion as `google/gemma-4-31b-it`. Consumers distinguish the execution
profiles by provider namespace while retaining convenient local naming.
Model names here illustrate identity and resolution, not provider availability
or a promise of maintained catalog entries.
The primary need is organization and convenient lookup within assembled
libraries, with backend, profile, and prompt collections managed independently
of PromptKit software releases. Ansible collections are a conceptual reference
for qualified names; a package manager and relocatable collection imports are
not required for this feature.
## Existing Foundation
The [format reference](../formats.md) defines prompt, profile, and backend keys
as exact literal IDs. Punctuation is already allowed, and references are not
trimmed or re-keyed. Merely adopting prefixed IDs therefore does not provide
the requested scoped lookup behavior.
Existing prompt and profile listings expose assembled identities. The
[consumer guide](../consumers/pkg-promptkit.md) describes current operations;
their Go declarations and GoDoc remain authoritative until this feature lands.
Directory-based and embedded configuration loading already exist through
`DirectoryInputs` and `FilesystemInputs`. The current engine also prepends
configuration assets from the imported OpenRouter and RakestrawHome Go modules,
plus PromptKit-owned profiles. Decision 4 removes that automatic inclusion and
dependency coupling; it does not require a replacement for ConfigKit loading.
[ADR 0001](../adr/0001-configuration-boundary.md) assigns source loading,
composition, and inheritance to ConfigKit. This proposal adds interpretation
of consumer-supplied resource names against the final effective configuration,
without a second source-composition pass.
## Accepted Identity Convention
Reserve `/` exclusively as the namespace separator in PromptKit prompt, profile,
and backend identifiers and references. A qualified identifier has exactly two
nonempty components: `namespace/local-name`. Neither component can contain `/`.
Dots remain available within local names. An unqualified identifier has no slash
and remains valid under the existing nonblank-ID rule.
Reject resource identifiers or supplied references with multiple slashes or an
empty qualified component, such as `a/b/c`, `/name`, and `namespace/`. These
rules do not apply to provider model values, endpoints, resource paths, or prompt
versions. Preserve exact spelling; do not silently trim or rewrite IDs.
| Resource | Namespace | Local name | Qualified ID |
| --- | --- | --- | --- |
| Prompt | `weatherreporter` | `summarize.alerts` | `weatherreporter/summarize.alerts` |
| Prompt | `homewatch` | `summarize.alerts` | `homewatch/summarize.alerts` |
| Profile | `openrouter` | `google.gemma-4-31b-it` | `openrouter/google.gemma-4-31b-it` |
| Profile | `rakestrawhome` | `google.gemma-4-31b-it` | `rakestrawhome/google.gemma-4-31b-it` |
Prompt, profile, and backend identities remain separate resource types. The
same namespace can contain all three, and resources in it may come from
multiple configuration sources. A namespace does not imply a directory,
package, provider model identifier, or security boundary.
A profile ID identifies execution settings. Its configured model value is
still the identifier passed to the provider; qualifying the profile ID does
not modify that value. Both example profiles may retain the configured model
`google/gemma-4-31b-it`. Different profiles may select the same model with
different settings. Prompt version labels remain separate from namespaces. The
selected collection format installs one definition per prompt ID and removes
request-side version selection and assertions. Optional labels are descriptive.
Retain unqualified and dotted IDs. Existing slash-containing IDs need review:
those with one slash and nonempty components become qualified identities, while
those outside the new grammar require migration. This intentional format break
is accepted in favor of unambiguous resolution; the migration work is described
below.
## Accepted Consumer Scope
Provide a lightweight, immutable view over an existing engine with independent
prompt, profile, and backend scopes. The following sketch illustrates the
accepted shape; method/type names and final signatures remain provisional:
```go
weather, err := engine.WithNamespaces(Namespaces{
Prompt: "weatherreporter",
Profile: "openrouter",
})
// Handle err, then use local prompt and profile names through weather.
```
This sketch follows [decision 1](#1-public-scope-shape-accepted); these
declarations do not exist yet.
The view would share the engine's captured configuration, clients, and execution
machinery. Selecting a namespace would not rebuild the engine or duplicate its
backend capacity accounting. Consumers could use different views concurrently
without changing a shared current-namespace setting.
The accepted resolution rules, independent of the final scope API, are:
1. A supplied name without a slash is qualified using the selected scope for its
resource type, then looked up exactly. Without that scope, it is looked up as
an exact unqualified ID.
2. A missing scoped resource does not trigger a search in other namespaces or
among unqualified IDs. Loading another collection cannot redirect lookup.
3. A valid supplied name containing one slash is fully qualified and is looked
up exactly, regardless of scope. Malformed resource references are rejected.
4. Scope applies to caller-supplied resource names. Stored references, including
prompt default profiles, profile backends, inheritance references, and backend
smoke-test default profiles, retain their existing exact meaning. They are
not rebound to the invoking consumer's namespace.
5. Omitted optional IDs retain their existing selection/default behavior; an
omission is not converted into a namespace prefix or a lookup for an empty
local name.
6. Where outputs, inspection, errors, or diagnostic reports identify a selected
resource, preserve its resolved full identity. Any exposed local name should
be distinguishable from that identity.
Keep qualification consistent across execution, preparation, request validation,
prompt/profile inspection, and applicable smoke-test selections. Namespace
selection must not change request override precedence or provider model strings.
Prompts resolve by ID alone.
### Local And Qualified References In One Operation
Syntax alone distinguishes local and qualified references. Do not decide whether
to qualify a name by checking which candidates exist; that would make resolution
depend on loaded content.
Within a `weatherreporter` prompt scope, `summarize.alerts` resolves only to
`weatherreporter/summarize.alerts`, while `homewatch/summarize.alerts` explicitly
selects that other library's prompt. A qualified profile override similarly
bypasses the profile scope. Scoped operations accept both forms without a
separate reference type or requiring a return to the original engine for
cross-namespace access.
The original engine remains the way to select an exact unqualified ID without
applying a scope. No escape syntax for unqualified IDs is introduced here.
### Separate Resource Scopes
A consumer can select prompt shorthand under `weatherreporter` and profile
shorthand under `openrouter` in the same request. Each resource type has an
independent scope, as defined in [decision 1](#1-public-scope-shape-accepted).
A prompt's configured default profile needs no caller profile scope because
the stored reference is already exact. Scope syntax and existence handling are
defined in [decision 2](#2-scope-validation-accepted).
## Discovery And Collection Organization
Namespace enumeration and filtering are integrated into PromptKit's listing
APIs. Consumers select a filter and receive matching full resource identities;
they do not need to fetch all resources and filter them themselves. Defaults,
explicit filter overrides, and result semantics are defined in
[decision 3](#3-discovery-accepted).
Derive namespace membership from the qualified identifier's namespace component:
`weather` must not include `weatherreporter/...`. Nested slash-separated
namespaces are outside the accepted grammar.
Collection namespace/release metadata and an API for reporting effective
collection declarations are desired additions. They are distinct from resource
namespace enumeration. Their configuration shape and specification-version
handling are accepted in [decision 5](#5-collection-metadata-and-specification-versioning-accepted).
## Composition And Compatibility
Qualified identities reduce accidental collisions between independently
authored libraries. Definitions with the same exact qualified identity still
follow the existing ConfigKit overlay and inheritance rules; namespaces do not
create a separate collision policy.
Leave source composition and configuration inspection with ConfigKit. Do not
introduce implicit qualification of definition keys, mounting under caller-chosen
prefixes, or rewriting of stored references as part of consumer scope. Those
would be separate configuration-design work.
ConfigKit owns all configuration processing before handing off the final,
fully resolved configuration. PromptKit must not add a collection-manifest
preflight, source-level uniqueness check, or independent version-checking pass
around that processing. Its domain interpretation and validation consume final
effective values. Source history remains available through explicit ConfigKit
inspection, not as a way to enforce extra assembly rules.
In particular, two documents contributing metadata for the same collection
namespace are governed by ordinary ConfigKit composition semantics. ConfigKit
may reject conflicts or combine contributions according to their layers; a
repeated source declaration is not an additional PromptKit error. The earlier
proposal to reject duplicate declared namespaces before composition is withdrawn.
Existing unscoped exact lookup remains available for IDs valid under the new
grammar. Compatibility with arbitrary slash-containing resource IDs is
intentionally broken. The migration must:
- Audit maintained catalogs and representative consumer definitions for invalid
IDs and for valid one-slash IDs whose namespace meaning needs review.
- Choose explicit old-to-new mappings and check for collisions. Do not
automatically replace slashes with dots: distinct existing IDs could collapse
to the same new identity.
- Update renamed keys and their references together, including inheritance,
prompt default profiles, profile backend references, backend smoke-test
defaults, and affected examples and consumer request IDs.
- Keep provider model strings unchanged. Renaming a profile does not rename
the upstream model.
- Document consumer action and coordinate the PromptKit format change with
catalog adoption under the [release policy](../policy/release.md). Its catalog
profile-data exception does not cover this general format/API behavior change;
deliberately retire its built-in-profile preservation promise when the
accepted removal lands. Current policy and format documents remain unchanged
until implementation.
Renaming a backend changes its identity; duplicating it under another ID can
separate capacity accounting. Do not use blanket aliases or duplicate catalog
entries as an automatic compatibility mechanism. Exact release versions and
catalog mappings remain implementation-planning work.
The [architecture policy](../policy/architecture.md) continues to assign CLI
syntax, flags, and application policy to consumers such as Scriptorium. PromptKit
would supply reusable scope and resolution semantics.
## Work Not Included In The Initial Proposal
- Package installation, collection registries, and dependency resolution.
- Automatic rewriting of stored references when mounting or renaming collections.
Explicit source destinations and namespace selection are supported by proposal 3.
- Implicit namespace search paths or fallback to whichever resource exists.
- Namespace-based access control or filesystem isolation.
- Changes to model names, inference behavior, or configuration precedence.
These boundaries limit the initial proposal; they do not prohibit future work
if a concrete consumer need emerges.
## Delivery Outline
1. Adopt the ConfigKit capabilities selected in decision 5 and audit existing
identifier usage against the accepted grammar. Record migration mappings and
application provisioning guidance. Finalize Go names and option types for
the accepted namespace and collection APIs.
2. Remove automatic catalog inclusion, catalog-module dependencies, and built-in
profiles under decision 4. Use caller-selected configuration sources and
update examples/tests to supply their own definitions.
3. Implement the smallest public scope surface with shared name qualification
and existing engine collaborators. Cover supported operations consistently.
4. Add integrated namespace filtering and representative consumer examples.
Implement collection metadata/inventory under the accepted decision 5.
5. Verify compatibility and scoped resolution through focused offline tests,
following the [testing policy](../policy/testing.md). Update GoDoc, the
format reference, consumer guide, and relevant internal documentation as
behavior lands; retire this roadmap when its work is complete.
Acceptance cases for the settled rules; the collection roadmap owns additional
configuration and metadata acceptance cases:
- Two prompt scopes resolve the same local name to their respective prompts;
a missing name never resolves from the other scope or an unqualified entry.
- Two provider profile scopes resolve the same local name, such as
`google.gemma-4-31b-it`, to different profiles without changing the configured
provider model value `google/gemma-4-31b-it`.
- A qualified reference bypasses the selected scope without double qualification;
adding another collection does not change local or qualified resolution.
- Multiple slashes and empty qualified components are rejected in resource IDs
and references, while provider model values retain their existing syntax.
- Prompt shorthand and a profile override use their intended scopes, while
stored default references and omitted selections retain their meaning.
- Scoped views coexist concurrently and share backend capacity with ordinary
calls on the underlying engine.
- Scope creation rejects invalid syntax, accepts well-formed absent namespaces,
and treats empty scope fields as no scope. Missing resources fail at lookup;
qualified references remain usable even when the default namespace is absent.
- Listing without an explicit filter uses the resource's view scope, or lists
all resources when no scope is selected. Explicit named, unqualified-only,
and all-namespaces filters override that default for the current listing only.
- A valid namespace with no matches produces an empty listing. Namespace
filtering respects resource type and exact namespace boundaries.
- Exact-ID calls using valid IDs and intentional overlays retain their behavior.
Migrated catalog references resolve without collisions; the collection roadmap
owns migration to one installed prompt and optional version labels.
- Listings preserve full IDs and separate optional prompt version labels.
Qualified results round-trip through either engine or view; unqualified results round-trip
through the engine without a corresponding scope.
- Representative validation, inspection, execution, and smoke-test paths use
the same qualification rules without duplicating every test at every layer.
- Engines use caller-selected definitions without automatically contributing
provider catalogs or PromptKit-owned profiles. Ordinary directory and embedded
configuration sources retain ConfigKit composition semantics.
- PromptKit does not add source-history-based duplicate-namespace rejection or
independently pre-validate collection definitions before the final handoff.
## Decisions And Pending Design
Decisions 1–3 are accepted; their alternatives are retained as considered but
not selected. Decision 4 records the accepted change in collection ownership
and supersedes the earlier catalog-only migration proposal. Decision 5 records
the accepted collection configuration direction and links its delivery details.
### 1. Public Scope Shape (Accepted)
**Accepted: an immutable view with independent resource scopes.** Provide one
engine operation that accepts a small value with prompt, profile, and backend
namespace fields and returns a scoped view or an error. The illustrative
`WithNamespaces` and `Namespaces` names above are provisional. Empty fields mean
no scope for that resource type. The view captures the value and delegates to
the same engine; it does not expose a mutable namespace setting. Apply the
prompt field to caller-supplied prompt IDs, the profile field to profile IDs,
and the backend field to backend IDs wherever those selections are supported.
Qualified references bypass the corresponding field.
This directly serves the select-once workflow and the common mixed case of an
application prompt namespace with a provider profile namespace. It also keeps
scope out of stored configuration and makes concurrent use independent of call
order. The cost is an additional facade surface whose supported operations must
remain consistent with the engine. Keep qualification shared rather than
duplicating selection logic in each wrapper.
Initially omit an ambiguous one-string `InNamespace` shorthand. Repeating the
same namespace in several fields happens once when creating a view and states
exactly which resource types it affects. A convenience operation can follow if
that repetition is a demonstrated burden.
**Considered alternative, not selected: one namespace per immutable view,
applied to all resource types.** A one-string operation would scope every
unqualified prompt, profile, and backend selection; callers would use qualified
references for resources in other namespaces. This is smaller and reads naturally for self-contained
application collections. It is less convenient when prompts and profiles
habitually come from different namespaces, because profile overrides would
repeatedly need qualification. Prefer it if consumers primarily use prompts'
configured defaults and rarely select profiles themselves.
**Considered alternative, not selected: explicit scope values supplied per
operation.** Add scope to request values and appropriate inspection/listing
options instead of returning a view. This makes every invocation self-contained
and suits applications that
choose a different scope for every request. It spreads scope through more call
sites and API shapes, and consumers would need their own reusable wrapper to
achieve the requested select-once experience. The immutable view is therefore
the better default for the use case discussed so far.
### 2. Scope Validation (Accepted)
**Accepted: validate syntax when creating the view; resolve existence when
an operation selects a resource.** In the scope value, the empty
string means no scope. Reject a nonempty namespace containing `/` or consisting
only of whitespace. Otherwise preserve its exact spelling, with no trimming,
case folding, or additional character whitelist. This distinguishes omission
from an unusable namespace without inventing normalization rules. Report invalid
scope construction through PromptKit's existing public error conventions.
Allow a well-formed namespace even when it has no current members. Its scoped
listing would be empty, and selection of a missing local resource would produce
the ordinary lookup error. Qualified selections would remain usable regardless
of the view's default scope. An empty optional request ID continues to mean
omission under that operation's existing contract; it is never qualified.
This keeps scope as a naming context and supports uniform application setup
across installations with different library contents. It also avoids treating
successful scope construction as validation of a prompt or execution profile.
The tradeoff is that a misspelled but syntactically valid namespace is detected
only when listed or used, rather than during view construction.
**Considered alternative, not selected: require each selected namespace to have
resources of its corresponding type when creating the view.** For an immutable
assembled engine, this can catch spelling mistakes immediately and gives startup checks useful
feedback without attempting execution. However, it rejects empty optional
collections and a view intended to use qualified references outside its default
namespace. A namespace having one member also does not establish that the
particular required prompt/profile exists. Prefer this approach only if eager
inventory validation is itself an intended consumer contract; it should not be
an accidental consequence of implementing scope creation.
### 3. Discovery (Accepted)
**Accepted: integrated namespace filtering and full-identity results.**
Enumerate the distinct named namespaces present in final effective
prompts, profiles, and backends. Allow filtering that enumeration by resource
type so a prompt picker need not show profile-only namespaces. Provide scoped
listings for the supported resource types, adding a backend inventory surface
as part of this work if needed. Namespace filtering is an explicit option in
the library listing API, not a consumer-side filtering helper. Preserve existing
unfiltered engine calls and their result contracts; the exact Go option shape
remains to be specified.
| Selection | Listing behavior |
| --- | --- |
| No explicit filter on the engine | All namespaces, including unqualified resources |
| No explicit filter on a scoped view | The selected scope for that resource type; all resources of that type if no scope is selected |
| Explicit named namespace | Resources in exactly that namespace |
| Explicit unqualified-only filter | Resources whose IDs have no namespace |
| Explicit all-namespaces filter | All resources of that type, including unqualified resources |
An explicit filter replaces the view's default for the current listing; it
does not intersect with that default or mutate the view. A named namespace
filter uses the namespace syntax rules in decision 2. A well-formed namespace
with no matching resources returns an empty listing. Represent default, named,
unqualified-only, and all-namespaces selections distinctly in the API; do not
overload an empty string to mean several of them.
Return full IDs with optional prompt version labels separately; the full ID
identifies the installed prompt. Do not invent a named namespace such as `default`
for unqualified resources. Namespace enumeration excludes that unnamed group.
Use deterministic ordering consistent
with existing listing contracts.
Qualified result IDs can be passed unchanged to either scoped or unscoped
operations. Unqualified IDs remain literal unqualified identities: when an
explicit all-namespaces or unqualified-only filter exposes one through a scoped
view, use the original engine or a view without that resource scope to select
it exactly. A listing filter does not change subsequent execution scope. This
preserves the accepted lookup rules without introducing an escape syntax.
Integrated filtering gives consumers a direct way to discover the desired
resources, while full identities keep logs and subsequent selections
unambiguous. Namespace/local-name display decomposition is separate from
filtering; a public splitting helper is not required by this decision.
**Considered alternative, not selected: add a richer inventory API returning
full ID, namespace, local name, resource type, and prompt version where
applicable.** Preserve existing list methods and expose the structured form
separately. This is attractive for
Scriptorium-style library browsers: grouping and display require no parsing,
and one inventory operation can cover all resource kinds. It creates another
public representation and overlaps existing listing APIs, so its value should
justify that maintenance. Prefer it if downstream clients routinely need a
combined catalog view rather than a resource picker or namespace filter. In
either approach, the full ID remains the authoritative selection value.
### 4. Collection Ownership And Built-In Removal (Accepted)
**Accepted: load collections as application/operator-supplied configuration,
and remove PromptKit's built-in profiles as a breaking change.** Remove the
mandatory OpenRouter and RakestrawHome catalog Go-module dependencies and their
automatic contribution to engine configuration. PromptKit owns the definition
format and execution machinery; collection publishers own their configuration
repositories, and applications/operators select and provision the collections
they use. One or more explicitly selected directories can supply backends,
profiles, and prompts through the existing ConfigKit integration.
Remove `promptkit-openrouter-standard` and `promptkit-openrouter-auto`, including
their implicit catalog dependencies. Do not replace them with another mandatory
starter bundle. Applications may embed their own defaults using the same
configuration format and loader, then layer operator configuration as desired.
Ordinary application overrides remain valid configuration and need not declare
a collection release of their own.
This decouples collection updates from PromptKit rebuilds and releases and
avoids imposing provider inventories on every consumer. The tradeoff is that
applications and deployments must supply their required configuration and
manage compatible collection revisions. PromptKit does not gain a collection
installer, automatic downloader, or implicit directory search policy.
Retain the captured-engine lifecycle: configuration changes take effect when
the application constructs and validates a replacement engine. A change to an
installed directory does not mutate an existing engine's captured definitions.
Distribution as configuration does not make new provider protocols or diagnostic
adapters data-only features; those can still require implementation work.
Prepare explicit identifier mappings, replacement configuration examples, and
consumer migration instructions. Update the built-in-profile promise in the
release policy and its canonical format documentation when removal lands.
Use a release permitted to break configuration and API contracts under the
current release policy: a minor release before v1, or a major release at/after
v1. Actual catalog mappings, packaging arrangements, and release versions remain
delivery work; independent collection releases need not track future PromptKit
software releases.
**Superseded alternatives:** retaining catalog Go modules with renamed profiles,
or retaining a small PromptKit-owned starter bundle, would simplify initial
provisioning but preserve some provider-data coupling. The accepted direction
places optional defaults in consuming applications and removes those core
dependencies instead.
### 5. Collection Metadata And Specification Versioning (Accepted)
**Accepted direction: [mounted collections](configuration-collections-mounted-fragments.md).**
Proposal 3 is the active configuration roadmap. It uses collection-local mapping
keys, one installed definition per prompt, and an optional flat prompt version.
Input destinations, relative imports, and shared source-version checks are
implemented in ConfigKit's reviewed development branch. PromptKit still needs
to adopt a suitable dependency release and implement its new schema.
Use shared specification checking with `IfPresent` and distinct collection
`release_version` metadata. Collection entries can describe their layout through
relative imports; applications select their sources and namespaces. PromptKit
interprets the final collection/resource keys as qualified IDs after ConfigKit's
handoff. It adds no manifest pre-parser, source-level namespace ownership rule,
or history-based validation pass. Stored references remain exact public IDs.
Proposals 1 and 2 were not selected and have been retired. Their original
contents and the separately preserved ConfigKit identified-record request are
recorded in the collection roadmap's
[retirement note](configuration-collections-mounted-fragments.md#retired-alternatives-and-upstream-request).
The record-sequence request is independent future upstream work and does not
block the selected mapping design.
The collection roadmap owns the candidate schema, examples, version policies,
metadata inventory, and migration requirements. Inventory describes effective
collection declarations captured by the engine, not historical manifests or
proof of unchanged published releases. Source explanation remains ConfigKit's
inspection concern.
The [six configuration decisions](configuration-collections-mounted-fragments.md#accepted-configuration-decisions)
are now accepted: optional main declarations, if-present checking without a new
strict-mode option, no global ban on resources named `version`, removal of
request-version machinery, existing ConfigKit inheritance, and flexible source
assembly with a small convenience API. Entry names and layouts are conventions;
consumers retain source and precedence choices. Cross-path inheritance and
stricter header options are deferred, not prerequisites.
No configuration-policy question remains open from that discussion. Exact API
signatures, metadata representations, dependency release selection, and migration
examples remain [delivery details](configuration-collections-mounted-fragments.md#remaining-delivery-details).
Removal of bundled catalogs and built-in profiles remains accepted.