# Framework Format Reference ## Purpose This is the canonical reference for Promptkit's backend, profile, prompt, and schema definitions. The [Go consumer guide](consumers/pkg-promptkit.md) shows how to select sources and use an engine; the [OpenAI-compatible integration contract](integrations/openai-compatible-chat.md) owns outbound wire behavior. [ConfigKit](https://gitea.maximumdirect.net/eric/ConfigKit) owns the generic YAML grammar, imports, layering, inheritance, and diagnostics. This reference describes what Promptkit does with the final effective values. A configuration document has keyed top-level `backends`, `profiles`, and `prompts` mappings. Their keys are literal IDs, not filename-derived identities. Each prompt ID maps directly to one definition; an optional `version` string is descriptive metadata, not a selection key. Keys and references must be nonblank and remain exact: Promptkit does not trim or re-key them. Old embedded `id` and `base_profile` fields are invalid. Unknown fields are errors. ```yaml backends: local: endpoint: http://localhost:8000/v1 concurrency_limit: 2 profiles: local-summary: backend: local model: example-model prompts: meeting.summary: version: "1.0.0" default_profile: local-summary messages: - role: user content: Summarize this note. output: format: text validation_mode: none ``` Every effective backend, profile, and prompt definition is validated when `NewEngine` constructs the engine, even if it is never selected. A profile may be partial: an endpoint and model need only be complete after request overrides are applied. A prompt's default profile similarly need not be runnable without an overriding request. Missing request data, artifacts, schemas, credentials, and provider work remain runtime concerns. The engine captures effective definitions, referenced message-file contents, and static template syntax at construction. It does not reread configuration or message files on ordinary runs; construct a new engine to observe edits. Schema and request artifact reads still happen during preparation. Use `InspectConfiguration` for an explicit effective-configuration or provenance report, `InspectProfile` for backend-completed profile settings, and preparation for request-specific rendered details. For identity discovery before inspection, see the consumer guide's [profile and prompt listing](consumers/pkg-promptkit.md#discover-available-profiles-and-prompts). ## Prompt Definitions The `prompts` mapping selects a literal prompt ID whose value is the definition: ```yaml prompts: meeting.summary: version: "1.0.0" default_profile: local-summary description: Summarize a synthetic meeting note. session_id: '{{.session}}' inputs: - name: note required: true content_type: text/plain description: Meeting note to summarize. messages: - role: system content: Return a concise summary. cache_control: type: ephemeral ttl: 1h - role: user content_file: ./summary.user.md output: format: markdown validation_mode: basic repair_attempts: 0 ``` `messages` must be nonempty and `output` must be a valid mapping. Optional `default_profile`, `description`, `session_id`, `inputs`, and cache-control fields may be absent or cleared with null where appropriate. A null whole definition, required role, output format, or validation mode is invalid. `required` and `repair_attempts` default to false and zero, respectively, and are not nullable. `InspectPrompt` selects the same captured definition without rendering or resolving a profile. ### Inputs Each `inputs` item may contain `name`, `required`, `content_type`, and `description`. `name` is required, nonblank, and unique within the prompt. Omitted `required` means false. Null `inputs` means no declarations. Requests supply inline or file-backed `ArtifactRef` values; declared required inputs must be present. A template reference also needs its named input, even when undeclared. Extra request inputs are allowed. ### Messages And Templates Each message needs a role and exactly one nonnull `content` or `content_file`. An explicitly empty inline `content` is valid. Null clears either content selection. Roles are trimmed and lowercased, then must be `developer`, `system`, `user`, or `assistant`. Static template syntax is checked during construction; missing variables and named inputs fail when rendered. Request variables are template data (`{{.audience}}`), and `{{input "note"}}` renders an input body. `content_file` uses the effective field's own source context, including when inherited or imported. Its relative path is resolved against that source's base directory within its rooted filesystem. Absolute paths and lexical escapes from the selected root fail. Host-file sources also prevent symlink escapes. Promptkit preserves the path text, including meaningful whitespace, after checking that it is not blank. A source without a unique usable resource context must supply one explicitly or override the field. Content is captured at construction, not reopened for each request. Optional `session_id` uses the same template variables and input helper. Its rendered value is trimmed, omitted if empty, and limited to 256 Unicode code points. A nonblank direct request session ID bypasses the template. `InspectRequirements` can enumerate recognizable dependencies from captured templates before artifact content is available. Its conservative syntax coverage does not change template validity or rendering; see the [consumer guide](consumers/pkg-promptkit.md#inspect-requirements-before-preparation) and the method's [GoDoc](../requirements.go) for that inspection boundary. ### Cache Control Optional `cache_control` has required `type: ephemeral` and optional `ttl`, which may be empty or `1h`. Promptkit retains this metadata on rendered messages; the integration contract defines its wire representation. ### Output Contract | Field | Required | Values or behavior | | --- | --- | --- | | `format` | yes | `text`, `markdown`, or `json` | | `validation_mode` | yes | `none`, `basic`, `json`, or `json_schema` | | `schema_path` | for `json_schema` | Path in the selected schema source | | `repair_attempts` | no | Integer 0–3; default 0. Positive values need `basic`, `json`, or `json_schema` | `none` skips content validation; `basic` requires nonempty content; `json` accepts any valid JSON value; `json_schema` checks the selected schema. `format` determines output artifact metadata. JSON Schema mode also supplies structured-output metadata to compatible clients. Plain `json` does not request a provider-native JSON-object constraint. A positive repair budget counts additional generations after failed validation; exhaustion returns the last candidate and its failed validation result. Operational errors remain errors. A request-level `OutputContract` replaces the whole configured one, not individual fields; an empty request format defaults to `text`. ## Built-In Backends The selected catalog modules contribute these backend definitions as the earliest underlay. Their settings can be overlaid by caller sources; these IDs are not reserved against configuration changes. | ID | Catalog endpoint | API-key environment name | Active generation limit | | --- | --- | --- | ---: | | `openrouter` | `https://openrouter.ai/api/v1` | `OPENROUTER_API_KEY` | 16 | | `rakestrawhome` | `https://inference.ai.rakestrawhome.com/v1` | `RAKESTRAWHOME_INFERENCE_API_KEY` | 4 | A backend definition may have `endpoint`, `api_key_env`, `concurrency_limit`, `queue_capacity`, `extra_params`, and `smoke_tests`. The final endpoint is required and must be an absolute HTTP(S) URL with a host, no user information, query, or fragment. An omitted or null API-key environment name means no lookup. Omitted/null concurrency is zero (unlimited); a supplied negative value is invalid. For positive concurrency, omitted/null queue capacity defaults to 1024. An explicit queue capacity, including zero, requires positive concurrency and must be nonnegative. Unlimited concurrency has no queue. Provider maps contain JSON-compatible values; null entries are ordinary JSON null. Unknown fields, including a raw `api_key`, fail. `smoke_tests` is optional backend metadata for explicit diagnostic operations. It may contain `default_profile`, `reachability`, and `authentication`: ```yaml backends: openrouter: smoke_tests: default_profile: promptkit-openrouter-standard reachability: endpoint: https://status.example/ready?check=1 authentication: kind: openrouter_key endpoint: https://openrouter.ai/api/v1/key ``` An omitted or null `smoke_tests` block disables these metadata defaults. `default_profile` is preserved as an exact, nonblank profile ID; its existence is checked only if an inference diagnostic selects that default. Omitted/null `default_profile` means there is no inference default. Omitted/null `reachability` or its endpoint uses the effective backend endpoint. An explicit reachability endpoint is trimmed and must be an absolute HTTP(S) URL with a host; unlike the backend base endpoint, its path and query are allowed. Null means fallback, while an explicit blank value is invalid. Omitted/null `authentication` means no authentication adapter is declared. A non-null object requires `kind`, which is trimmed and case-normalized; the recognized values are `none` and `openrouter_key`. Its omitted/null endpoint uses the adapter's backend-relative destination (`openrouter_key` appends `/key` to the effective backend base); an explicit endpoint follows the same full-URL rules as reachability. `none` declares authentication inapplicable. These values are configuration only: engine construction does not contact a backend. These fields are resolved through the ordinary ConfigKit source layers before Promptkit validates the final effective values. A higher-priority mapping can override individual nested fields; an explicit null can clear the whole `smoke_tests` block or one of its nested objects. An endpoint set to null uses its documented fallback, while an explicit blank endpoint is invalid. The metadata does not change ordinary generation credential requirements or provider settings. The selected v3 catalog modules ship diagnostic defaults in a separate, opt-in `smoke-tests` root rather than changing the existing `catalog` root. This Promptkit build selects [OpenRouter v3 `v3.20261013.0`](oss/attribution.md#promptkit-openrouter-catalog-v3) with default profile `promptkit-openrouter-standard` and adapter `openrouter_key`, and [Rakestrawhome v3 `v3.20261013.0`](oss/attribution.md#promptkit-rakestrawhome-catalog-v3) with default profile `rakestrawhome-gemma-4-31b` and adapter `none`. The attribution entries identify the selected module commits; these catalog candidates are local and may not be publicly available. A consumer selecting the extra root needs a compatible loader. These defaults do not promise provider availability, account access, or free test requests. ## Profile Definitions Profiles are keyed by literal ID and may inherit a named parent with `extends`: ```yaml profiles: local-summary: backend: local model: example-model temperature: 0.2 max_tokens: 500 timeout_seconds: 90 extra_params: provider_option: enabled local-summary-fast: extends: local-summary timeout_seconds: 30 reasoning_effort: low ``` Profiles may also supply `endpoint`, `top_p`, `service_tier`, `api_key_env`, and `api_key_required`. Promptkit does not infer a backend from an endpoint or model. A profile with only an endpoint has no backend capacity identity. Nonblank endpoints follow the backend URL rules; temperature is 0–2, top_p is 0–1, max_tokens and timeout_seconds are nonnegative. Provider maps accept JSON-compatible values with nonempty keys and cannot collide with the built-in client's [standard request fields](integrations/openai-compatible-chat.md#request-body). Credential values do not belong in profiles: raw `api_key` is invalid. ### Defaults And Overrides After effective profile inheritance, Promptkit applies the selected backend's defaults once, then request `ExecutionTargetOverride` values. Backend-derived settings are not inheritance input: changing a child profile's backend does not carry the parent's derived endpoint or credential source into it. Changing only a model or backend does not clear unrelated explicitly inherited fields. | Profile field | Absent | Explicit value | Explicit null | | --- | --- | --- | --- | | `backend` | No backend | Exact backend ID; blank means none | No backend | | `endpoint` | Selected backend endpoint | Valid nonblank URL; empty clears | Clear, without backend fallback | | `model` | Unspecified | Nonblank model; empty clears | Unspecified | | `temperature`, `top_p`, `max_tokens` | Unspecified | Valid value, including outbound zero | Suppress outbound control | | `service_tier`, `reasoning_effort` | Unspecified | Normalized value; blank suppresses | Suppress outbound control | | `timeout_seconds` | 600 seconds | Nonnegative; zero disables generation deadline | Reset to 600 seconds | | `api_key_env` | Backend lookup name, if any | Trimmed name; blank disables | Disable backend lookup | | `api_key_required` | False | Boolean, including false | False | | `extra_params` | Backend defaults | Recursively overlay profile map on backend map | Suppress configured provider map | An empty mapping does not clear inherited map entries; null clears the whole map. Nested maps merge recursively, while scalar and array values replace. Runtime nonempty `ExtraParams` overrides replace the entire configured map. Request overrides otherwise follow the [public value GoDoc](../types.go). For example, a runtime `extra_params["extends"]` key is ordinary provider data, not a configuration inheritance instruction. An explicit zero timeout does not disable the caller context or HTTP transport timeout. ### Source And Profile Precedence `NewEngine` composes catalog definitions first, Promptkit-owned definitions next, then caller underlays in their given order, with an optional main input last. Later tiers overlay earlier ones. Inputs within one underlay group are strictly composed: conflicting contributions are errors, not priority signals. The directory helpers discover `.yaml` and `.yml` files recursively in sorted order, but that order does not give one file higher precedence. An explicitly selected missing/unreadable root fails; an empty root contributes nothing. Imports are disabled by these helpers unless the caller enables them on an input. Single files can use ConfigKit inputs directly. Backends, profiles, and prompts all follow these same source rules. A later profile or backend can change individual fields of a lower definition. A request `ProfileID` takes precedence over a prompt `default_profile`; if neither is selected, preparation fails. Exact profile inspection selects one explicit ID and does not consult a prompt default. ### Profile Inheritance ConfigKit resolves `extends` on effective profile definitions. One profile may inherit another keyed profile; presence, explicit null, and recursively merged maps determine the final fields. References are literal IDs, including IDs containing punctuation. There is no Promptkit-specific depth limit or second base-chain resolver. Missing references and cycles fail at construction. For generic inheritance and layer mechanics, consult [ConfigKit](https://gitea.maximumdirect.net/eric/ConfigKit). ## Built-In Profile Catalog Promptkit contributes two opt-in definitions; neither is selected by default: | ID | Current definition | | --- | --- | | `promptkit-openrouter-standard` | Extends the selected OpenRouter catalog's `gemini-flash-latest` profile. | | `promptkit-openrouter-auto` | Selects backend `openrouter` and model `openrouter/auto`. | Select one through request `ProfileID` or prompt `default_profile`. Caller layers may overlay these definitions or their catalog bases. The [release policy](policy/release.md#catalog-profile-compatibility) owns their cross-version compatibility boundary. ## External Profile Inventories The selected catalog modules, not this document, own their profile inventories: - [OpenRouter catalog v3.20261013.0 profiles](https://gitea.maximumdirect.net/eric/promptkit-backend-openrouter/src/tag/v3.20261013.0/catalog/profiles) - [Rakestrawhome catalog v3.20261013.0 profiles](https://gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/src/tag/v3.20261013.0/catalog/profiles) These are tested local data, not a promise of live provider availability. The [release policy](policy/release.md#catalog-profile-compatibility) owns the compatibility boundary. ## Schemas Schemas are JSON documents selected by a prompt or request `schema_path`. Directory and `fs.FS` schema paths resolve within the configured root; referenced nested schemas resolve relative to the owning schema document. `WithSchemaFile` exposes one schema under its base name. An unreadable, invalid, or unresolvable schema causes an operational validation error. Valid JSON that fails the schema instead yields a failed validation result. ## Credentials Only environment-variable names belong in backend/profile definitions, never credential values. A request may supply a direct `APIKey` or an `APIKeyEnv` override. A direct key takes precedence, followed by a request environment source, an explicit profile source, and an inherited backend source. A true profile `api_key_required` suppresses the backend-derived environment source, but an explicit profile or request environment source remains usable. False restores ordinary optional-credential behavior. Missing or blank optional environment values leave the built-in client's Authorization header absent; required availability is checked at preparation and again during prepared execution. Injected clients own their credential-resolution behavior. Credential values are excluded from JSON results and redacted by public string formatters. ConfigKit inspection redacts credential-shaped dynamic provider keys, but does not make arbitrary prompt/provider content safe to disclose. Applications own report disclosure and secret handling.