13 KiB
Namespaces And Scoped Resource Lookup
Status: proposed feature roadmap; not implemented. The consumer need is established, but the API shape and naming rules below remain proposals unless identified as existing behavior.
Purpose
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. Ansible collections are a conceptual reference for qualified names; package distribution and relocatable collection imports are not required for this feature.
Existing Foundation
The format reference 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 describes current operations; their Go declarations and GoDoc remain authoritative until this feature lands.
ADR 0001 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.
Proposed Identity Convention
Use namespace/local-name as the qualified identifier. The first slash is the
namespace boundary; the rest of the local name is literal and may contain dots
or additional slashes. This is the recommended convention, not a settled
format change.
| 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. Different profiles may select the same model with different settings. Prompt versions also remain separate from namespaces and continue to use the existing selection rules.
Retain existing exact IDs, including unqualified and dotted names. Before formalizing namespace discovery, audit slash-containing IDs in maintained catalogs and representative consumer configurations: interpreting their first component as a namespace may affect grouping even when exact lookup is unchanged.
Proposed Consumer Scope
Prefer a lightweight, immutable view over an existing engine. The following sketch illustrates the consumer experience only; it does not settle a method name, return type, error behavior, or final signature:
weather := engine.InNamespace("weatherreporter")
// Operations through weather can select the local prompt "summarize.alerts".
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 proposed resolution rules are:
- A supplied local name is qualified using the selected scope for its resource type, then looked up exactly.
- A missing scoped resource does not trigger a search in other namespaces or among unqualified IDs. Loading another collection cannot redirect lookup.
- An operation without a selected scope retains existing exact-ID behavior.
- 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.
- 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.
- 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, prompt version selection, or provider model strings.
Local Names Versus Exact IDs
The presence of a slash cannot distinguish local and qualified references:
google/gemma-4-31b-it is a legitimate local profile name under openrouter.
Do not decide whether to qualify a name by checking whether the unqualified
candidate happens to exist; that would make resolution depend on loaded content.
The recommended initial approach is that a scoped resource field consistently accepts a local name, while the original engine remains available for exact IDs. Under that approach, even a string that looks qualified is treated as local when passed through the corresponding scope. An explicit per-reference exact-ID mechanism is an alternative if mixed local and qualified selections in one request justify it. Settle this before defining the public API.
Separate Resource Scopes
A consumer may want prompt shorthand under weatherreporter and profile
shorthand under openrouter in the same request. Evaluate independently
selectable prompt, profile, and backend scopes instead of assuming one namespace
must apply to every field. A prompt's configured default profile needs no caller
profile scope because the stored reference is already exact.
Independent scopes are recommended where the consumer needs shorthand, but the
scope options and the meaning of a convenience InNamespace operation are
still open. Do not silently apply a prompt scope to an otherwise exact profile
override. Include any directly supplied backend selection in this decision.
Discovery And Collection Organization
Namespace-aware discovery is supporting work: consumers should be able to identify available namespaces and list their resources without each application inventing parsing and filtering rules. Keep this proportionate to the primary scoped-lookup feature.
Decide whether scoped listing returns full identities, local names alongside full identities, or another explicit shape. A caller must be able to tell how to pass a listed name back to a scoped operation without double qualification. Retain the existing unscoped listing contracts.
If namespace membership is derived from the recommended prefix convention,
match the complete namespace boundary: weather must not include
weatherreporter/.... Additional slashes within the local name do not imply
recursive namespace traversal.
The initial proposal does not require a collection manifest. Titles, descriptions, and other collection metadata can be considered if consumers need more than identity and grouping.
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.
Existing unscoped engine calls and catalog identifiers must continue to work. Adoption of the new convention by maintained catalogs needs an explicit migration decision. Renaming a profile or backend can affect configured references; duplicating a backend under another ID can also separate capacity accounting. Do not treat blanket aliases or duplicate catalog entries as a cost-free compatibility mechanism.
The architecture policy 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.
- Caller-selected collection mount points or import alias rewriting.
- 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
- Settle the open naming and API decisions below and audit existing identifier usage. Record any catalog migration as explicit coordinated work.
- Implement the smallest public scope surface with shared name qualification and existing engine collaborators. Cover supported operations consistently.
- Add the selected discovery behavior and representative consumer examples.
- Verify compatibility and scoped resolution through focused offline tests, following the testing policy. Update GoDoc, the format reference, consumer guide, and relevant internal documentation as behavior lands; retire this roadmap when its work is complete.
Suggested acceptance cases, subject to the selected API contract:
- 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 preserve a slash-containing local name and select different profiles without changing the configured provider model value.
- 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.
- Existing exact-ID calls, intentional overlays, and prompt versions retain their behavior.
- Listings and reported identities support the chosen local/full-ID round trip.
- Representative validation, inspection, execution, and smoke-test paths use the same qualification rules without duplicating every test at every layer.
Open Decisions
- Naming convention: adopt the first-slash boundary, or select another separator? What namespace syntax is needed without narrowing existing IDs?
- Public scope shape: immutable view, scope options, or another small surface? Which resource scopes can be selected independently, and what does a one-namespace convenience operation mean?
- Exact access within scoped requests: use the original engine for exact selections, or provide an explicit per-reference distinction?
- Scope validation: when should an empty, malformed, or currently absent namespace produce an error? Distinguish syntax from resource existence and do not accidentally change omitted-ID defaults.
- Discovery: which listing/filtering operations are needed, how are legacy IDs grouped, and how are local and full identities represented?
- Catalog adoption: which maintained IDs, if any, should change, and what compatibility and release plan would accompany those changes?
Resolve these choices before treating the proposed mechanics as implementation requirements. The central requirement is already clear: consumers select a scope once and use local names predictably within an assembled library.