284 lines
15 KiB
Markdown
284 lines
15 KiB
Markdown
# Namespaces And Scoped Resource Lookup
|
|
|
|
Status: feature roadmap; not implemented. The reserved-slash naming convention
|
|
and reference-resolution rules are accepted target behavior. The public scope
|
|
API, discovery surface, and migration details remain open as identified below.
|
|
|
|
## 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.
|
|
|
|
## 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 versions also remain separate from namespaces and
|
|
continue to use the existing selection rules.
|
|
|
|
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.
|
|
|
|
## 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 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, prompt version selection,
|
|
or provider model strings.
|
|
|
|
### 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 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. Define which scopes apply to unqualified names in each request
|
|
field; qualified references always bypass them. 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.
|
|
|
|
Derive namespace membership from the qualified identifier's namespace component:
|
|
`weather` must not include `weatherreporter/...`. Nested slash-separated
|
|
namespaces are outside the accepted grammar.
|
|
|
|
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 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;
|
|
account for its explicitly retained built-in profile names when selecting
|
|
migrations.
|
|
|
|
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.
|
|
- 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 API decisions below and audit existing identifier usage
|
|
against the accepted grammar. Record explicit mappings and coordinated
|
|
migration 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.
|
|
|
|
Acceptance cases for the settled rules, with scope/discovery details 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 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.
|
|
- Existing exact-ID calls using valid IDs, intentional overlays, and prompt
|
|
versions retain their behavior. Migrated catalog references resolve to their
|
|
intended resources without collisions.
|
|
- 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. **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?
|
|
2. **Scope validation:** how does the scope API represent no scope, report an
|
|
invalid namespace selection, and handle a well-formed but currently absent
|
|
namespace? Apply the accepted separator rules, distinguish syntax from
|
|
existence, and preserve omitted-ID defaults. Do not add case folding or other
|
|
character restrictions without a separate decision.
|
|
3. **Discovery:** which listing/filtering operations are needed, how are legacy
|
|
IDs grouped, and how are local and full identities represented?
|
|
4. **Catalog migration:** what exact old-to-new mappings and coordinated release
|
|
plan will implement the accepted breaking change, and which otherwise valid
|
|
IDs should additionally adopt provider/application namespaces?
|
|
|
|
The delimiter, two-component qualified grammar, syntax-based resolution, and
|
|
acceptance of the required breaking migration are settled. Resolve the remaining
|
|
API and delivery choices around that foundation: consumers select a scope once
|
|
and use local or explicitly qualified names predictably within an assembled
|
|
library.
|