Files
promptkit/docs/roadmap/namespaces.md

15 KiB

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

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:

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