# Framework Format Reference ## Purpose This document is the canonical contract for Promptkit prompt-definition, profile, and schema files. The [Go package consumer guide](consumers/pkg-promptkit.md) explains how to select these sources and invoke the engine. The [OpenAI-compatible integration contract](integrations/openai-compatible-chat.md) owns the resulting outbound wire behavior. Prompt and profile sources recursively discover files ending in `.yaml` or `.yml`. YAML decoding is strict: unknown fields are errors for the selected definition. Definitions are selected by their YAML `id`, not their file name or directory. ## Prompt Definitions A prompt definition describes inputs, Go-template messages, an optional default profile, and an output contract. ```yaml id: 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 ``` | Field | Required | Meaning | | --- | --- | --- | | `id` | yes | Non-empty prompt identifier used by `RunRequest.PromptID`. | | `version` | yes | Non-empty version selected by an optional `RunRequest.PromptVersion`. | | `default_profile` | no | Non-empty profile ID used when the request omits `ProfileID`. | | `description` | no | Human-readable description. | | `session_id` | no | Go template rendered from request variables and input helpers. | | `inputs` | no | Declared input metadata. | | `messages` | yes | One or more chat-message templates. | | `output` | yes | Output format and validation settings. | When a request omits a version, the selected prompt ID must identify exactly one definition. When it supplies a version, the ID and version pair must be unique. ### Inputs Each `inputs` item has these fields: | Field | Required | Meaning | | --- | --- | --- | | `name` | yes | Non-empty name used by the request input map and `input` template helper. Names must be unique. | | `required` | no | When true, preparation fails if the request omits the input. The default is false. | | `content_type` | no | Expected media-type metadata. | | `description` | no | Human-readable input description. | Requests supply inputs as inline or file-backed `ArtifactRef` values. Declared required inputs must be present. A template reference also requires the named input to exist, whether or not it was declared. Extra request inputs are allowed. ### Messages And Templates Each message has a non-empty `role` and exactly one of: - `content`, containing an inline Go template; or - `content_file`, naming a file whose contents are the Go template. For directory and `fs.FS` prompt sources, `content_file` resolves relative to the prompt file and remains within the source root. `WithPromptFile` also resolves it relative to that file. Request variables are the template data, so a variable named `audience` is referenced as `{{.audience}}`. The `{{input "note"}}` helper renders the body of a named input. Missing variables and input references are errors. The optional `session_id` uses the same template data and input helper. Its rendered value is trimmed, omitted when empty, and limited to 256 Unicode code points. A nonblank direct request session ID bypasses this template completely; a blank direct value leaves the template behavior unchanged. ### Cache Control `cache_control` is optional and has these fields: | Field | Required | Values | | --- | --- | --- | | `type` | yes | `ephemeral` | | `ttl` | no | Empty or `1h` | Promptkit preserves cache-control metadata on the rendered message. The outbound integration determines 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 to a schema in the configured schema source. | | `repair_attempts` | no | Integer zero or greater; omitted means zero. | The validation modes behave as follows: - `none` skips content validation; - `basic` requires non-empty generated content; - `json` requires valid JSON; and - `json_schema` requires valid JSON that satisfies the selected schema. `format` controls output artifact metadata. JSON Schema mode also supplies the schema to compatible model clients as structured-output metadata. The public engine does not install an output repairer, so its validation is single-pass even when a positive `repair_attempts` value is present. A request-level `OutputContract` replaces the complete prompt output contract. It does not merge individual fields. If its format is empty, Promptkit uses `text`. ## Profile Definitions A profile supplies model execution settings: ```yaml id: local-summary backend: openrouter model: example-model temperature: 0.2 max_tokens: 500 top_p: 0.95 timeout_seconds: 90 service_tier: flex reasoning_effort: medium extra_params: provider_option: enabled ``` | Field | Required | Meaning | | --- | --- | --- | | `id` | yes | Non-empty profile identifier. IDs must be unique within one source. | | `backend` | unless `endpoint` is present | Backend registry ID. It is trimmed and registry membership is checked when the profile is prepared. | | `endpoint` | unless `backend` is present | Non-empty OpenAI-compatible base URL, including an API version path when required. When both connection fields are present, this overrides the backend endpoint without changing backend identity. | | `model` | yes | Non-empty provider model name. | | `temperature` | no | Number from 0 through 2. | | `max_tokens` | no | Integer zero or greater. | | `top_p` | no | Number from 0 through 1. | | `timeout_seconds` | no | Per-generation deadline in whole seconds; integer zero or greater. | | `service_tier` | no | Provider-specific request tier. | | `reasoning_effort` | no | Provider-specific reasoning setting. | | `api_key_env` | no | Name of an environment variable containing the API key. | | `extra_params` | no | JSON-compatible provider-specific outbound fields. | Raw `api_key` is prohibited in profile YAML. Store only an environment variable name in `api_key_env`. Promptkit does not infer a backend from a model or endpoint. Endpoint-only profiles remain supported and have no effective backend ID. The engine always provides the built-in `openrouter` ID. Consumers can add engine-scoped IDs with [`WithBackend`](../backends.go); exact registration validation belongs to its GoDoc. `extra_params` accepts null, booleans, finite numbers, strings, arrays, and objects with string keys. Keys must be non-empty. With the built-in client, they also cannot collide with the standard fields listed in the [outbound request contract](integrations/openai-compatible-chat.md#request-body). ### Defaults And Overrides Execution settings resolve in this order: 1. framework defaults; 2. the selected backend, when the profile names one; 3. the selected profile; and 4. request `ExecutionTargetOverride` values. The framework defaults are: | Setting | Default | | --- | --- | | `temperature` | `0` | | `max_tokens` | `0` | | `top_p` | `1` | | `timeout_seconds` | `600` | Numeric zero in a file or in-memory profile means that the profile does not replace the framework default. Numeric request overrides use pointers, so an explicit zero is preserved. In particular, an explicit request `timeout_seconds` of zero disables the per-generation deadline while leaving the caller context and transport timeout intact. Non-empty profile strings replace backend defaults, and non-empty request strings replace both. Request reasoning is the exception: a nil `ReasoningEffort` pointer inherits the profile, a pointer to a nonblank string trims and replaces it, and a pointer to a blank string clears it. Backend identity is retained when either layer overrides the endpoint, so the override also retains any engine-local capacity policy configured for that backend. Capacity configuration belongs to the Go [`Backend` API](../backends.go), not prompt or profile YAML. A non-empty `extra_params` map at each layer replaces the entire lower-precedence map rather than merging keys. The [outbound integration contract](integrations/openai-compatible-chat.md) defines how the effective settings are serialized. ### Source And Profile Precedence An explicit request profile ID takes precedence over the prompt's `default_profile`. If neither is present, preparation fails. Profile sources resolve matching IDs in this order: 1. in-memory profiles supplied with `WithProfiles`; 2. a profile file, `fs.FS`, or configured profile directory; and 3. embedded built-in profiles. A higher-precedence source falls back only when the profile is absent. An invalid matching profile is an error and does not fall back. In-memory `Profile` values follow the same ranges as YAML profiles. They use `APIKeyRequired` for request-scoped credentials instead of `api_key_env`. ## Built-In Profile Catalog Every built-in selects the `openrouter` backend. The engine's built-in backend registry supplies `https://openrouter.ai/api/v1` and the environment-variable name `OPENROUTER_API_KEY`, so individual profiles contain only model and generation settings. Built-in profile files do not repeat those connection values. A custom or in-memory profile with the same profile ID takes precedence. | Provider | ID | Model | | --- | --- | --- | | aion-labs | `aion-2` | `aion-labs/aion-2.0` | | anthropic | `claude-fable-latest` | `~anthropic/claude-fable-latest` | | anthropic | `claude-haiku-latest` | `~anthropic/claude-haiku-latest` | | anthropic | `claude-opus-latest` | `~anthropic/claude-opus-latest` | | anthropic | `claude-sonnet-latest` | `~anthropic/claude-sonnet-latest` | | deepseek | `deepseek-3-2` | `deepseek/deepseek-v3.2` | | deepseek | `deepseek-4-flash` | `deepseek/deepseek-v4-flash` | | deepseek | `deepseek-4-pro` | `deepseek/deepseek-v4-pro` | | google | `gemini-2-flash` | `google/gemini-2.5-flash` | | google | `gemini-2-flash-lite` | `google/gemini-2.5-flash-lite` | | google | `gemini-2-pro` | `google/gemini-2.5-pro` | | google | `gemini-3-flash-lite` | `google/gemini-3.1-flash-lite` | | google | `gemini-flash-latest` | `~google/gemini-flash-latest` | | google | `gemini-pro-latest` | `~google/gemini-pro-latest` | | google | `gemma-4-31b` | `google/gemma-4-31b-it:exacto` | | minimax | `minimax-m2` | `minimax/minimax-m2.5` | | minimax | `minimax-m3` | `minimax/minimax-m3` | | mistral | `mistral-large-2512` | `mistralai/mistral-large-2512` | | mistral | `mistral-medium-3-5` | `mistralai/mistral-medium-3-5` | | mistral | `mistral-small-3` | `mistralai/mistral-small-3.2-24b-instruct` | | mistral | `mistral-small-4` | `mistralai/mistral-small-2603` | | nvidia | `nemotron-3-ultra` | `nvidia/nemotron-3-ultra-550b-a55b` | | openai | `gpt-5-mini` | `openai/gpt-5.4-mini` | | openai | `gpt-5-nano` | `openai/gpt-5.4-nano` | ## Schemas Schemas are JSON documents selected by a prompt or request `schema_path`. For a directory or `fs.FS` source, paths resolve within the configured source root. Referenced nested schemas resolve relative to the owning schema document. `WithSchemaFile` exposes one schema, addressed by its base name. An unreadable, invalid, or unresolvable schema produces an operational validation error. Generated content that is valid JSON but does not satisfy the schema produces a failed validation result. ## Credentials Credential values belong at the request or environment boundary, never in prompt, profile, schema, or example files: - a file profile names an environment variable with `api_key_env`; - an in-memory profile may set `APIKeyRequired`; - a request can provide a direct `APIKey` or override `APIKeyEnv`; and - a direct request key takes precedence over environment lookup. After a direct request key, the credential-source precedence is request `APIKeyEnv`, profile `api_key_env`, then the backend default. An in-memory profile with `APIKeyRequired` clears an inherited backend environment name and requires a direct key unless the request explicitly supplies `APIKeyEnv`. Promptkit validates required credential availability during preparation. Direct keys are excluded from JSON results and redacted by public string formatters. Environment-variable names may appear in prepared metadata, but their values do not.