# Configuration Reference ## Config Discovery And Precedence Application settings are loaded in this order: 1. Built-in defaults 2. `config.yml` values 3. CLI overrides When `--config` is not provided, Scriptorium searches for config files in this order: 1. `/usr/local/etc/scriptorium/config.yml` 2. `/etc/scriptorium/config.yml` If neither file exists, Scriptorium continues with built-in defaults. When `--config ` is provided, that file is required. ## Minimal App Config ```yaml prompt_dir: ./examples/prompts ``` This is enough to use `run` and `render` when prompts select built-in profiles. ## Production-Oriented App Config ```yaml prompt_dir: /opt/scriptorium/prompts profile_dir: /opt/scriptorium/profiles schema_dir: /opt/scriptorium/schemas server: addr: 127.0.0.1:8080 defaults: render_format: text ``` ## App Config File (`config.yml`) Top-level fields: - `prompt_dir` (optional): default prompt definition directory. - `profile_dir` (optional): default custom profile definition directory. - `schema_dir` (optional): base directory for schema files used by `json_schema` validation. - `server.addr` (optional): default listen address for `serve`. - `defaults.render_format` (optional): default `render` output format (`text` or `json`). Built-in defaults: - `schema_dir`: `.` - `server.addr`: `:8080` - `defaults.render_format`: `text` Validation behavior: - Config decoding is strict; unknown YAML fields are rejected. - Raw API key fields are not supported in `config.yml`. ## Prompt Definition Files Prompt definitions are YAML files anywhere under `prompt_dir`, including nested subdirectories. Subdirectories are organizational only. Callers still select prompts by the YAML `id`, not by file path. For example, `prompts/dnd/recap.yaml` may still declare `id: dnd.recap`, and callers use `--prompt dnd.recap`. Example: ```yaml id: generic.structured_events version: "1.0.0" default_profile: local-quality description: Produce structured event JSON from a transcript. inputs: - name: transcript required: true content_type: text/markdown description: Source transcript content - name: glossary required: false content_type: text/yaml description: Optional glossary context messages: - role: system content_file: ./generic.structured_events.system.md - role: user content_file: ./generic.structured_events.user.md output: format: json validation_mode: json_schema schema_path: structured_events.schema.json repair_attempts: 0 ``` Field reference: - `id` (required): prompt identifier. - `version` (required): prompt version. - `default_profile` (optional): profile ID used when request does not provide `profile_id`. - `description` (optional): prompt description. - `session_id` (optional): Go-template string for OpenRouter sticky-routing `session_id`; rendered from request vars. - `inputs` (optional list): expected named inputs. - `messages` (required list): prompt message templates. - `output` (required object): output contract. `inputs[]` fields: - `name` (required) - `required` (optional, boolean) - `content_type` (optional metadata) - `description` (optional) `messages[]` fields: - `role` (required) - `content` or `content_file` (exactly one is required) - `cache_control` (optional object): provider prompt-cache metadata for this message Message rules: - Repeated roles are allowed. - `content_file` is resolved relative to the prompt YAML file location. - Nested prompt files keep the same relative `content_file` behavior; `./recap.user.md` next to `dnd/recap.yaml` resolves from `dnd/`. - Prompt decoding is strict; unknown YAML fields are rejected. - Duplicate prompt IDs are invalid. If multiple files declare the requested prompt ID, Scriptorium fails instead of choosing one. `messages[].cache_control` fields: - `type` (required when `cache_control` is present): currently only `ephemeral`. - `ttl` (optional): currently only `1h`; omitted from outbound requests when unset. Example cache-controlled message: ```yaml messages: - role: system content_file: ./stable_context.md cache_control: type: ephemeral ttl: 1h - role: user content: | {{input "transcript"}} ``` Use cache control on stable reusable prompt content. Dynamic per-run inputs before the cache-controlled message change the provider cache key. Example prompt-level session ID: ```yaml session_id: "{{ .session_id }}" ``` When configured, `session_id` is rendered with the same variable context as messages. The rendered value is trimmed, omitted when empty, and rejected if longer than 256 characters. CLI callers pass the value through `--var session_id=`; HTTP callers pass it through `"vars": {"session_id": ""}`. `output` fields: - `format` (required): `text`, `markdown`, or `json`. - `validation_mode` (required): `none`, `basic`, `json`, or `json_schema`. - `schema_path` (required when `validation_mode: json_schema`). - `repair_attempts` (required): integer `>= 0`. Repair behavior boundary: - `repair_attempts` is part of the prompt contract. - CLI and HTTP currently construct the runner without a repairer, so normal `run`/`serve` execution does not perform output repair attempts. ## Profile Definition Files Scriptorium includes built-in execution profiles. Custom execution profiles are YAML files anywhere under `profile_dir`, including nested subdirectories. Subdirectories are organizational only. Callers still select profiles by the YAML `id`, not by file path. For example, `profiles/local/local-quality.yaml` may still declare `id: local-quality`, and callers use `--profile local-quality`. Example: ```yaml id: local-fast endpoint: http://localhost:8000/v1 model: gpt-4o-mini temperature: 0.2 max_tokens: 500 top_p: 1.0 timeout_seconds: 90 api_key_env: SCRIPTORIUM_API_KEY service_tier: priority reasoning_effort: medium extra_params: provider_route: primary provider_options: retry_budget: 2 ``` Field reference: - `id` (required) - `endpoint` (required) - `model` (required) - `temperature` (optional): range `0..2` - `max_tokens` (optional): `>= 0` - `top_p` (optional): range `0..1` - `timeout_seconds` (optional): `>= 0` - `service_tier` (optional): provider-specific request tier such as OpenRouter `flex` or `priority` - `reasoning_effort` (optional): serialized as top-level `reasoning_effort` in outbound chat-completions requests - `api_key_env` (optional) - `extra_params` (optional map): JSON-compatible provider-specific parameters. Values may be strings, numbers, booleans, objects, or arrays. Profile rules: - `profile_dir` is optional. If omitted, only built-in profiles are available. - If `profile_dir` is set, custom profiles from that directory override built-in profiles with the same `id`. - Duplicate IDs within the custom profile directory are invalid. Matching IDs across custom and built-in profiles are valid override behavior. - Profile decoding is strict; unknown YAML fields are rejected. - Raw `api_key` is rejected; use `api_key_env`. - If `api_key_env` is set, that environment variable must be set when preparing/running. - Duplicate profile IDs are invalid. If multiple files declare the requested profile ID, Scriptorium fails instead of choosing one. - `extra_params` keys must not be empty and must not collide with reserved outbound request fields: `model`, `session_id`, `messages`, `temperature`, `max_tokens`, `top_p`, `service_tier`, `reasoning_effort`, or `response_format`. Current outbound request behavior: - The OpenAI-compatible client currently serializes: `model`, optional `session_id`, `messages`, `temperature`, `max_tokens`, `top_p`, `service_tier`, `reasoning_effort`, optional `response_format` for `json_schema` prompts, and `extra_params`. - `extra_params` are flattened into provider-specific top-level JSON request fields. They are not wrapped in an `extra_params` object on the outbound provider request. - Messages without `cache_control` serialize with string `content`. - Messages with `cache_control` serialize as a single text content-block array containing `cache_control`. ## Schema Behavior Schemas are JSON files, typically in `schema_dir`. Rules: - `output.validation_mode: json_schema` requires `output.schema_path`. - Relative `schema_path` values resolve from `schema_dir`, including explicit nested paths such as `dnd/structured_events.schema.json`. - Absolute `schema_path` values are used directly. - Scriptorium does not recursively search schemas by basename; nested schemas must be referenced by their relative path. - Missing or invalid schema documents cause runtime validation errors. - Invalid generated JSON causes validation status `failed` (not a runtime error). Supported artifact reference types for request inputs are `file` and `inline`. ## Secrets Handling - Keep secret values in environment variables. - Store only environment-variable names in profile `api_key_env`. - Do not put raw API keys in config, prompts, profiles, CLI flags, or HTTP request bodies. ## Maintained Examples - App config: `examples/config.yml` - Prompt examples: `examples/prompts/` - Custom profile examples: `examples/profiles/` - Schema examples: `examples/schemas/` - Input fixtures: `examples/fixtures/` - Render example script: `examples/render-markdown-summary.sh` - HTTP request example: `examples/http-run.json` Example organizational layout: ```text examples/prompts/dnd/recap.yaml examples/profiles/local/local-quality.yaml examples/schemas/dnd/structured_events.schema.json ``` ## Integration References - [Inbound HTTP contract](integrations/http-api.md) - [Outbound OpenAI-compatible contract](integrations/openai-compatible-chat.md)