# 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.