Document namespace and scoped lookup roadmap

This commit is contained in:
2026-10-13 21:25:57 +00:00
parent 5dc6370a97
commit 75891b6561

244
docs/roadmap/namespaces.md Normal file
View File

@@ -0,0 +1,244 @@
# 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](../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.
[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.
## 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:
```go
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:
1. A supplied local name is qualified using the selected scope for its resource
type, then looked up exactly.
2. A missing scoped resource does not trigger a search in other namespaces or
among unqualified IDs. Loading another collection cannot redirect lookup.
3. An operation without a selected scope retains existing exact-ID behavior.
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, 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](../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.
- 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
1. Settle the open naming and API decisions below and audit existing identifier
usage. Record any catalog migration as explicit coordinated work.
2. Implement the smallest public scope surface with shared name qualification
and existing engine collaborators. Cover supported operations consistently.
3. Add the selected discovery behavior and representative consumer examples.
4. 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.
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
1. **Naming convention:** adopt the first-slash boundary, or select another
separator? What namespace syntax is needed without narrowing existing IDs?
2. **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?
3. **Exact access within scoped requests:** use the original engine for exact
selections, or provide an explicit per-reference distinction?
4. **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.
5. **Discovery:** which listing/filtering operations are needed, how are legacy
IDs grouped, and how are local and full identities represented?
6. **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.