18 KiB
Framework Format Reference
Purpose
This document is the canonical contract for Promptkit prompt-definition, profile, and schema files. The Go package consumer guide explains how to select these sources and invoke the engine. The OpenAI-compatible integration contract owns the resulting outbound wire behavior.
Prompt and profile sources recursively discover files ending in .yaml or
.yml. Each prompt-definition and profile file contains exactly one YAML
document; comments and trailing whitespace are allowed. 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.
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.
Exact prompt inspection uses this same configured source, strict decoding, referenced content-file resolution, and ID/version selection. It reports the selected definition's declared metadata without changing the prompt format or executing the definition.
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; orcontent_file, naming a file whose contents are the Go template.
content_file must be a relative path. It resolves from the directory that
contains the prompt file and must remain within the configured prompt source
root; parent components are allowed only when the resolved target remains
inside that root. Absolute paths and paths that escape the root are rejected.
Operating-system directory and single-file sources also reject symlink targets
outside the root, while injected fs.FS sources apply containment in that
filesystem's relative path namespace. For WithPromptFile, the source root is
the directory containing the selected prompt file. Promptkit uses the parsed
path text exactly after checking separately that it is not blank, so leading
and trailing whitespace can name real filesystem entries.
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:
noneskips content validation;basicrequires non-empty generated content;jsonrequires valid JSON; andjson_schemarequires 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.
Built-In Backends
Every engine provides these reserved OpenAI-compatible backend IDs. Consumers
must not register either ID with WithBackend; exact registration and
reservation behavior belongs to the Backend GoDoc.
| ID | Base endpoint | API-key environment variable | Active generation limit | Default queue capacity |
|---|---|---|---|---|
openrouter |
https://openrouter.ai/api/v1 |
OPENROUTER_API_KEY |
16 | 1024 |
rakestrawhome |
https://inference.ai.rakestrawhome.com/v1 |
RAKESTRAWHOME_INFERENCE_API_KEY |
4 | 1024 |
Profile Definitions
A profile supplies model execution settings:
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
A derived profile can use a named base and override only the settings it owns:
id: local-summary-fast
base_profile: local-summary
timeout_seconds: 30
reasoning_effort: low
| Field | Required | Meaning |
|---|---|---|
id |
yes | Profile identifier, trimmed before selection and publication. It must be non-empty after trimming and unique within one source after normalization. |
base_profile |
no | One optional parent profile ID. A derived profile may inherit target fields from it. |
backend |
unless endpoint is present |
Backend registry ID. It is trimmed and registry membership is checked when the profile is prepared or inspected. |
endpoint |
unless backend is present |
OpenAI-compatible base URL, including an API version path when required. A nonempty value is trimmed and must be absolute HTTP or HTTPS with a host and without user information, a query, or a fragment. 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 | Optional environment-variable lookup source for an 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.
A standalone profile must provide a model and at least one of backend or
endpoint. A derived profile may omit those target fields because its selected
base chain can provide them. Local parsing still validates a derived profile's
own ID, supplied endpoint, execution-setting bounds, and extra_params.
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 and rakestrawhome IDs.
Consumers can add engine-scoped IDs with
WithBackend; 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.
Excessively deep or large JSON-shaped values are rejected for safety.
Defaults And Overrides
Execution settings resolve in this order:
- the framework timeout baseline;
- the selected backend, when the profile names one;
- the selected profile; and
- request
ExecutionTargetOverridevalues.
The framework baseline is:
| Setting | Default |
|---|---|
temperature |
Unspecified and omitted from compatible provider requests unless a profile or runtime override selects it. |
max_tokens |
Unspecified and omitted from compatible provider requests unless a profile or runtime override selects it. |
top_p |
Unspecified and omitted from compatible provider requests unless a profile or runtime override selects it. |
timeout_seconds |
600 |
Numeric zero in a file or in-memory profile does not select a numeric value.
For temperature, max_tokens, and top_p, it leaves the provider control
unspecified. For timeout_seconds, it retains the framework deadline. Numeric
request overrides use pointers, so an explicit zero is retained and sent to
compatible providers. 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, 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
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. Exact profile
inspection instead takes one explicit profile ID and does not use a prompt
default.
Profile sources resolve matching IDs in this order:
- in-memory profiles supplied with
WithProfiles; - the ordinary configured source selected by a profile file,
fs.FS, or configured profile directory; - application fallback profiles supplied with
WithFallbackProfileFS; and - embedded built-in profiles.
A profile source supplies a complete definition; definitions and their fields
are not merged across sources. A higher-precedence source falls back only when
the requested profile ID 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. Preparation and exact profile inspection use this same source
precedence.
When a selected definition names base_profile, every profile ID in that
chain is looked up through this same precedence order. A higher-precedence
definition therefore shadows a lower-precedence definition of the same base
ID, including a built-in. References are not source-qualified.
Profile Inheritance
Promptkit resolves one linear base chain of at most 32 profiles, including the
selected profile. It merges settings from the root base to the selected leaf.
The leaf's id remains the selected profile identity. Nonblank string fields
(backend, endpoint, model, service_tier, reasoning_effort, and
api_key_env) and nonzero numeric fields replace inherited values. A nonempty
extra_params map replaces the complete inherited map rather than merging
keys, and APIKeyRequired: true remains true through the chain. Backend and
endpoint are independent: replacing one does not clear the other.
There is no profile-level clearing syntax. Blank strings, zero numbers, false, and empty maps remain unspecified and inherit from a base. Use existing presence-aware request overrides where an execution needs an explicit zero or empty reasoning setting.
An absent directly selected profile reports the ordinary not-found error. Once the selected profile exists, a missing base, cycle, overlong chain, or incomplete resolved target is a profile-load failure. Ordinary operations resolve chains afresh; prepared execution retains the fully resolved target.
Built-In Profile Catalog
Every built-in profile selects one maintained built-in backend and inherits that backend's connection and credential metadata. Profile files do not repeat those values. A configured, application fallback, or in-memory profile with the same profile ID takes precedence.
| Provider | ID | Backend | Model |
|---|---|---|---|
| aion-labs | aion-2 |
openrouter |
aion-labs/aion-2.0 |
| anthropic | claude-fable-latest |
openrouter |
~anthropic/claude-fable-latest |
| anthropic | claude-haiku-latest |
openrouter |
~anthropic/claude-haiku-latest |
| anthropic | claude-opus-latest |
openrouter |
~anthropic/claude-opus-latest |
| anthropic | claude-sonnet-latest |
openrouter |
~anthropic/claude-sonnet-latest |
| deepseek | deepseek-3-2 |
openrouter |
deepseek/deepseek-v3.2 |
| deepseek | deepseek-4-flash |
openrouter |
deepseek/deepseek-v4-flash |
| deepseek | deepseek-4-pro |
openrouter |
deepseek/deepseek-v4-pro |
gemini-2-flash |
openrouter |
google/gemini-2.5-flash |
|
gemini-2-flash-lite |
openrouter |
google/gemini-2.5-flash-lite |
|
gemini-2-pro |
openrouter |
google/gemini-2.5-pro |
|
gemini-3-flash-lite |
openrouter |
google/gemini-3.1-flash-lite |
|
gemini-flash-latest |
openrouter |
~google/gemini-flash-latest |
|
gemini-pro-latest |
openrouter |
~google/gemini-pro-latest |
|
gemma-4-31b |
openrouter |
google/gemma-4-31b-it:exacto |
|
rakestrawhome-gemma-4-31b |
rakestrawhome |
google/gemma-4-31b-it |
|
| minimax | minimax-m2 |
openrouter |
minimax/minimax-m2.5 |
| minimax | minimax-m3 |
openrouter |
minimax/minimax-m3 |
| mistral | mistral-large-2512 |
openrouter |
mistralai/mistral-large-2512 |
| mistral | mistral-medium-3-5 |
openrouter |
mistralai/mistral-medium-3-5 |
| mistral | mistral-small-3 |
openrouter |
mistralai/mistral-small-3.2-24b-instruct |
| mistral | mistral-small-4 |
openrouter |
mistralai/mistral-small-2603 |
| nvidia | nemotron-3-ultra |
openrouter |
nvidia/nemotron-3-ultra-550b-a55b |
| openai | gpt-5-mini |
openrouter |
openai/gpt-5.4-mini |
| openai | gpt-5-nano |
openrouter |
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 backend or file profile can name an optional environment lookup source
with
APIKeyEnvorapi_key_env; - an in-memory profile may set
APIKeyRequiredas an explicit local requirement; - a request can provide a direct
APIKeyor override the optionalAPIKeyEnvsource; 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.
Named environment sources are optional: when the selected source is absent,
empty, or whitespace-only, the built-in client omits the Authorization
header and handles the provider response normally. APIKeyRequired is the
only explicit local availability requirement. Promptkit validates required
credential availability during preparation and rechecks it when a prepared
execution runs. Injected clients receive resolved source metadata but define
their own credential-resolution behavior.
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.