320 lines
16 KiB
Markdown
320 lines
16 KiB
Markdown
# PromptKit Feature Request: Configuration Input Destinations
|
|
|
|
Status: consumer feature request; not accepted or implemented.
|
|
|
|
## Requested Capability
|
|
|
|
Provide a public API through which a consumer can select a destination mapping
|
|
path for each configuration input. The input's application content contributes
|
|
beneath that path while retaining ConfigKit's normal composition, precedence,
|
|
inheritance, validation, diagnostics, and inspection behavior.
|
|
|
|
PromptKit needs this capability for its proposal 3, **Collections With Mounted
|
|
Configuration Fragments**, recorded in PromptKit's
|
|
`docs/roadmap/configuration-collections-mounted-fragments.md`. This request
|
|
describes the public API needs and observable acceptance criteria. It does not
|
|
prescribe ConfigKit's internal design or an implementation plan.
|
|
|
|
The reviewed public baseline is ConfigKit v0.7.1. The current
|
|
[layered-loading contract](../config.md#layered-loading) lets consumers choose
|
|
sources, import policy, filesystem context, and precedence groups, but does not
|
|
provide an input destination. Existing behavior remains authoritative until an
|
|
extension is adopted.
|
|
|
|
## Consumer Problem
|
|
|
|
PromptKit applications assemble independently maintained collections of prompts,
|
|
inference profiles, and backends. Collections can contain identical local names,
|
|
such as `summarize.alerts`, without identifying the same resource. PromptKit wants
|
|
an effective configuration organized by collection, while letting authors omit
|
|
repeated collection and resource-container wrappers from individual files.
|
|
|
|
A file selected from a collection's `prompts` directory 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
|
|
```
|
|
|
|
Given destination `[collections, weatherreporter, prompts]`, its contribution
|
|
would appear in the final application configuration as:
|
|
|
|
```yaml
|
|
collections:
|
|
weatherreporter:
|
|
prompts:
|
|
summarize.alerts:
|
|
version: "1"
|
|
default_profile: provider/brief
|
|
messages:
|
|
- role: user
|
|
content: Summarize the weather alerts.
|
|
output:
|
|
format: text
|
|
validation_mode: none
|
|
```
|
|
|
|
Another collection can contribute `summarize.alerts` beneath
|
|
`[collections, homewatch, prompts]` without conflicting. After final handoff,
|
|
PromptKit interprets these as `weatherreporter/summarize.alerts` and
|
|
`homewatch/summarize.alerts`. The profile reference is illustrative and must be
|
|
supplied separately by the application configuration.
|
|
|
|
PromptKit will support one installed definition per prompt. Its optional flat
|
|
`version` is ordinary domain metadata, not a merge identity. This request does
|
|
not need identified-record sequences, sequence-root documents, or a custom
|
|
merge policy.
|
|
|
|
Authors could write the complete wrappers today, but that repeats assembly
|
|
details in every fragment. Consumer-side parsing and wrapping would put generic
|
|
source processing back into PromptKit and complicate source attribution.
|
|
PromptKit instead wants to select sources and destinations, then receive one
|
|
final configuration through ConfigKit's supported loading lifecycle.
|
|
|
|
## Minimum Public API
|
|
|
|
### Per-Input Destination
|
|
|
|
Allow a destination to be attached to each `Input` passed to `LoadLayered`.
|
|
One possible public spelling is an optional `Destination Path` field on `Input`.
|
|
The name and exact signature are suggestions; equivalent public API designs
|
|
are welcome.
|
|
|
|
Illustrative consumer code using the proposed field, which does not exist in
|
|
v0.7.1:
|
|
|
|
```go
|
|
promptInput := configkit.Input{
|
|
Source: configkit.File("/usr/local/share/collections/weatherreporter/prompts/alerts.yml"),
|
|
Destination: configkit.Keys("collections", "weatherreporter", "prompts"),
|
|
}
|
|
|
|
peers := configkit.Underlay{
|
|
Inputs: []configkit.Input{promptInput},
|
|
}
|
|
```
|
|
|
|
The consumer would include `peers` in its existing `LayeredOptions` and invoke
|
|
`LoadLayered` with its normal root main input and application `Definition`.
|
|
This is a partial API sketch, not an executable example or a proposed new
|
|
loading entry point. A single public layered load is sufficient for PromptKit;
|
|
it does not require a separate mounting operation on completed results.
|
|
|
|
The API must let the consumer:
|
|
|
|
- Express a destination relative to the application configuration root using
|
|
literal mapping-key segments. Dots, slashes, and numeric-looking text inside
|
|
a key are not implicit path separators or array indexes. PromptKit's namespace
|
|
grammar remains its own domain rule.
|
|
- Omit the destination to retain existing root placement. An explicitly empty
|
|
destination should have the same meaning. Mapping destinations are sufficient;
|
|
sequence-index destinations are not needed by this request.
|
|
- Assign different destinations to inputs in the same strict composition group,
|
|
and assign the same destination to inputs in separate precedence groups.
|
|
- Use the destination with existing content-bearing source kinds: host files,
|
|
native filesystem files, bytes, readers, and mapping sources, subject to their
|
|
existing acquisition and ownership contracts.
|
|
- Retain the existing import opt-in and filesystem context independently of the
|
|
destination. A configuration destination is not a filesystem root or base
|
|
directory.
|
|
|
|
PromptKit can continue to enumerate an explicitly selected directory and attach
|
|
the same destination to its returned inputs. ConfigKit does not need a new
|
|
directory scanner, namespace registry, filename convention, or PromptKit schema.
|
|
The namespace comes from the application's assembly declaration, not from an
|
|
implicit interpretation of a directory basename.
|
|
|
|
### Representative Assembly
|
|
|
|
These are application choices, not ConfigKit-specific reserved paths:
|
|
|
|
| Selected inputs | Destination key segments |
|
|
| --- | --- |
|
|
| Application main document | Root |
|
|
| `weatherreporter/collection.yml` | `collections`, `weatherreporter` |
|
|
| YAML files under `weatherreporter/prompts` | `collections`, `weatherreporter`, `prompts` |
|
|
| YAML files under `homewatch/prompts` | `collections`, `homewatch`, `prompts` |
|
|
| YAML files under `provider/profiles` | `collections`, `provider`, `profiles` |
|
|
| YAML files under `provider/backends` | `collections`, `provider`, `backends` |
|
|
|
|
Peer collection contributions belong to a single strict underlay group when the
|
|
application wants conflict detection among them. Intentional operator overrides
|
|
use later groups or main. Destination selection must not establish precedence
|
|
or make source traversal order authorize replacement.
|
|
|
|
## Required Observable Behavior
|
|
|
|
### Composition And Precedence
|
|
|
|
Mounted and explicitly wrapped contributions must have equivalent application
|
|
values and conflict behavior at their effective destinations. Actual source
|
|
locations naturally differ and must remain accurate.
|
|
|
|
Retain the [strict composition](../config.md#strict-document-composition) and
|
|
[layering](../config.md#layered-loading) rules:
|
|
|
|
- Disjoint mapping entries at the same destination combine.
|
|
- Overlapping non-mapping values within a strict group conflict, including equal
|
|
scalars, nulls, and sequences. Different destinations do not collide merely
|
|
because the source documents share a local key.
|
|
- Later precedence layers recursively override mappings and replace other
|
|
values. A strict conflict cannot be repaired by an upper layer.
|
|
- Empty mappings do not clear lower definitions; ordinary arrays remain atomic.
|
|
In particular, `messages` does not acquire sequence-merging behavior.
|
|
- Overlapping destination paths and contributions at their ancestors follow
|
|
those same rules. No namespace-level uniqueness restriction is requested.
|
|
|
|
Changing only a prompt's `version` in a later layer changes that field while
|
|
retaining omitted lower-layer fields. ConfigKit must not treat a domain version
|
|
label as a request to replace an entire definition.
|
|
|
|
### Imports And Existing Structural Directives
|
|
|
|
An input with imports enabled must be able to use its existing source-root
|
|
`configkit.imports` directive while contributing application data at a nested
|
|
destination. The directive remains structural configuration, not an application
|
|
field below that destination.
|
|
|
|
For the minimum API, imports inherit their importing input's destination,
|
|
including transitive imports. Import paths continue to resolve relative to
|
|
their declaring source's filesystem context. A mounted document must not send
|
|
its imported application fields back to the configuration root accidentally.
|
|
|
|
Existing opt-in, containment, missing-input, cycle, and repeated-source behavior
|
|
must remain applicable. A different destination is not a request to bypass the
|
|
current rejection of a repeated physical source within a strict group.
|
|
|
|
Sibling `extends` must resolve against mappings at their effective destinations.
|
|
For example, two independently supplied profile fragments mounted beneath the
|
|
same collection's `profiles` mapping can establish `extends: brief` once they
|
|
compose. Inheritance remains ConfigKit-owned; PromptKit does not perform another
|
|
relationship-resolution pass.
|
|
|
|
### Protected Specification Paths
|
|
|
|
The distinction between source-local field names and effective application
|
|
paths is essential. PromptKit's main document will declare `version: 1` at the
|
|
configuration root. A separate collection metadata file can contain:
|
|
|
|
```yaml
|
|
version: "2.4.0"
|
|
```
|
|
|
|
Mounted at `[collections, weatherreporter]`, that field is an ordinary collection
|
|
release label. It must not be rejected as an attempt to contribute the protected
|
|
root specification field. The same applies to a prompt's nested optional
|
|
version. Only the main-owned specification declaration uses the application's
|
|
configured [VersionRule](../config.md#application-schema-versions).
|
|
|
|
Conversely, placement must not permit an underlay or imported fragment to claim
|
|
or replace the actual protected specification path or an ancestor that would
|
|
replace it. The public contract must define protection in terms of effective
|
|
application paths, rather than reserving the spelling `version` in every source.
|
|
Protection must remain valid with imports, inheritance, overlays, and explicit
|
|
CLI overrides.
|
|
|
|
PromptKit needs one main-owned specification check with the existing lifecycle.
|
|
It does not need main mounted away from the root, integer-to-string conversion
|
|
for every nested `version`, or separate compatibility checks for every fragment.
|
|
|
|
### Typed Loading, Diagnostics, And Inspection
|
|
|
|
The destination must be visible consistently through the ordinary public
|
|
loading and inspection surface:
|
|
|
|
- Final typed configuration and application callbacks use effective destination
|
|
paths. Defaults, resolution, and validation retain the existing single-load
|
|
lifecycle; fragments are not independently validated as whole applications.
|
|
- Metadata and presence queries distinguish omission, explicit null, and other
|
|
explicit values at the mounted paths.
|
|
- Diagnostics identify the effective conflicting or invalid path and the real
|
|
contributing source locations. Consumers can determine which source and
|
|
placement produced a value without recreating that relationship themselves.
|
|
- Effective rendering, explanations, history, and configuration comparison agree
|
|
with the final configuration. Existing sensitivity and disclosure rules apply
|
|
to mounted fields, including application path-based secret classification.
|
|
- Unsupported destination forms and destination-related loading failures use
|
|
the normal structured error boundary. Exact new diagnostic codes, if needed,
|
|
are for ConfigKit to define.
|
|
|
|
PromptKit does not require a separate mount registry or new inspection facade.
|
|
Existing inspection APIs are sufficient if they expose accurate effective paths,
|
|
source attribution, and placement information. ConfigKit should document how
|
|
source-local locations relate to effective paths.
|
|
|
|
### Source-Relative Resources And Lifecycle
|
|
|
|
For a mounted field such as `content_file: ./summary.md`, obtaining its effective
|
|
origin and calling `Result.SourceContext` or `Resolution.SourceContext` must
|
|
still identify the declaring source's filesystem and base directory. The same
|
|
holds when that field survives an override or is inherited into another mapping.
|
|
Its configuration destination must not change the meaning of the relative file
|
|
reference.
|
|
|
|
Retain existing source ownership, load completion, result lifetime, containment,
|
|
and resource-access behavior. Destinations must participate in documented load
|
|
limits without creating a way to bypass them; this request does not prescribe
|
|
new limit values or their accounting machinery.
|
|
|
|
## Optional Follow-Ups, Not Prerequisites
|
|
|
|
**Import destinations in YAML.** A destination on an import directive could let
|
|
publishers describe assembly in configuration rather than Go. Proposal 3
|
|
recommends destinations relative to the importing document's destination, with
|
|
omission retaining that destination. This is useful, but per-input placement
|
|
through the public API is sufficient for initial PromptKit adoption. No new
|
|
directive spelling is selected by this request.
|
|
|
|
**Independent specification headers.** A collection entry document might later
|
|
declare its own supported specification version. That needs a distinct contract
|
|
for checking the header and determining its role in the composed configuration.
|
|
Mounting collection release metadata does not supply this capability. Keep it a
|
|
separate request if PromptKit decides it is necessary.
|
|
|
|
**Cross-collection inheritance.** Nested collection profiles are not immediate
|
|
siblings across collections. Current sibling inheritance remains sufficient for
|
|
the initial proposal, with authored definitions flattened where necessary.
|
|
Generic cross-path inheritance could be considered separately if consumer needs
|
|
justify revisiting the [deferred scope](deferred.md). Mounting must not silently
|
|
reinterpret `extends: provider/brief` as a cross-collection reference.
|
|
|
|
PromptKit also does not request collection installation, automatic directory
|
|
discovery, remote fetching, namespace ownership enforcement, dependency solving,
|
|
live reload, filename-derived identity, or arbitrary document transformations.
|
|
Its qualified resource IDs, optional prompt version semantics, collection
|
|
inventory, and execution APIs remain PromptKit responsibilities.
|
|
|
|
## Public Acceptance Scenarios
|
|
|
|
Evaluate the extension through supported public loading and inspection APIs:
|
|
|
|
| Scenario | Expected consumer-visible result |
|
|
| --- | --- |
|
|
| Destination omitted or empty | Existing root-placement behavior |
|
|
| Same fragment shape mounted under two distinct collection keys from independent sources | Two separate effective resources |
|
|
| Disjoint inputs at the same destination in one group | Mapping contributions combine |
|
|
| Equal or unequal overlapping scalar fields in one group | Structured composition conflict with both source locations |
|
|
| Same destination across deliberate precedence tiers | Existing recursive overlay behavior |
|
|
| Version-only prompt override | Label changes; omitted prompt body fields survive |
|
|
| Nested mounted import without a destination directive | Imported fields contribute at the inherited destination |
|
|
| Local profile inheritance across mounted peer fragments | Parent resolves at the effective sibling scope |
|
|
| Collection metadata containing `version` mounted below root | Ordinary nested field, independent of root VersionRule |
|
|
| Mounted/imported contribution actually targeting the protected version path | Rejected under version ownership rules |
|
|
| Mounted field using source-relative content, including inheritance | Original declaring resource context remains available |
|
|
| Mounted explicit null and omitted field | Distinct effective presence information |
|
|
| Mounted validation error or secret field | Effective paths, physical locations, and existing disclosure rules agree |
|
|
| File, native filesystem, byte, reader, or mapping input with equivalent content | Equivalent application values, subject to existing source contracts |
|
|
| Unsupported destination or failed load | Normal structured failure, no usable partial result |
|
|
|
|
The minimum usable outcome is a consumer that selects collection sources and
|
|
destinations, performs one ordinary layered load, and receives final typed
|
|
configuration with reliable diagnostics and inspection. It should need no
|
|
consumer-side source rewriting, generic merging, or provenance reconstruction.
|