Consolidate collection and namespace roadmaps
This commit is contained in:
@@ -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.
|
|
||||||
845
docs/roadmap/configuration-collections.md
Normal file
845
docs/roadmap/configuration-collections.md
Normal 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.
|
||||||
@@ -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.
|
|
||||||
Reference in New Issue
Block a user