diff --git a/README.md b/README.md index a67e91c..7fea7db 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@ # scriptorium -Scriptorium is a config-driven prompt execution engine. +Scriptorium is a narrow prompt-execution application for rendering prompt +requests, running them against OpenAI-compatible chat-completions endpoints, and +serving the same run workflow over HTTP. -It separates prompt definitions (what to generate) from execution profiles (how to call an OpenAI-compatible model endpoint), then runs or renders a prepared request from named input artifacts. +It keeps prompt definitions, execution profiles, schemas, and input artifacts as +separate files so prompts can be reviewed and reused without baking model +runtime settings into application code. ## Quickstart @@ -23,16 +27,19 @@ This command renders the prepared prompt and effective runtime settings without - [CLI reference](docs/cli.md) - [Configuration reference](docs/config.md) +- [HTTP API reference](docs/api.md) - [Operations guide](docs/operations.md) - [Troubleshooting](docs/troubleshooting.md) +- [Consumer integration overview](docs/consumers/api.md) - [Go library package](docs/consumers/pkg-scriptorium.md) -- [HTTP API reference](docs/api.md) -- [OpenAI-compatible chat integration](docs/integrations/openai-compatible-chat.md) - [Subprocess integration](docs/integrations/subprocess.md) +- [OpenAI-compatible chat integration](docs/integrations/openai-compatible-chat.md) - [Architecture policy](docs/policy/architecture.md) ## Examples +- `examples/config.yml` +- `examples/config.full.yml` - `examples/render-markdown-summary.sh` - `examples/http-run.json` - `examples/go-library/prepare` diff --git a/docs/cli.md b/docs/cli.md index b7fb23f..94a4d22 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -10,127 +10,195 @@ go run ./cmd/scriptorium render \ --input glossary=./examples/fixtures/glossary.yml ``` -`render` prepares and formats the prompt without calling an LLM. +`render` prepares the prompt, loads input artifacts, resolves the execution +profile, and prints the prepared request without calling an LLM. ## Command Overview -- `scriptorium run`: prepare prompt, call the configured LLM, write generated output, print a run summary. -- `scriptorium render`: prepare prompt only; write prepared-run output as `text` or `json`. -- `scriptorium serve`: start the HTTP server. +- `scriptorium run`: prepare a prompt, call the configured LLM, write generated output, and print a run summary. +- `scriptorium render`: prepare a prompt only; write prepared-run output as `text` or `json`. +- `scriptorium serve`: start the HTTP server for `POST /v1/runs`. -Integration references: +Canonical related references: +- [Configuration reference](config.md) - [HTTP API reference](api.md) - [Subprocess integration](integrations/subprocess.md) -## Common Argument Rules +## Common Rules - `--config` is supported by `run`, `render`, and `serve`. -- `run` and `render` require: - - `--prompt` - - at least one `--input` - - an effective `prompt_dir` from flags or config -- `serve` requires an effective `prompt_dir` from flags or config. -- `profile_dir` is optional. If omitted, only built-in profiles are available; if provided, custom profiles override built-ins with the same ID. -- Built-in profile IDs are listed in the [configuration reference](config.md#profile-definition-files). - Positional arguments are rejected. -- Prompt cache control is configured in prompt YAML (`messages[].cache_control`), not with CLI flags. -- Provider-specific `reasoning_effort` and `extra_params` are configured in profile YAML or HTTP model overrides, not with CLI flags. +- `run` and `render` require `--prompt`, at least one `--input`, and an effective `prompt_dir`. +- `serve` requires an effective `prompt_dir`. +- `profile_dir` is optional. Without it, only built-in profiles are available. +- If `profile_dir` is set, custom profiles override built-in profiles with the same ID. +- Prompt cache control, `session_id`, structured output, and provider-specific profile fields are configured in YAML, not with CLI flags. + +Config precedence is: + +1. built-in defaults +2. config file values +3. CLI flags ## Flag Reference ### `scriptorium run` -- `--config `: app config file path. +```bash +scriptorium run [flags] +``` + +Required through flags or config: + - `--prompt-dir `: prompt definition directory. + +Required as flags: + +- `--prompt `: prompt ID to execute. +- `--input name=path`: input file mapping. Repeat or use comma-separated mappings. + +Optional flags: + +- `--config `: application config file. - `--profile-dir `: custom profile definition directory. - `--schema-dir `: schema base directory for `json_schema` validation. -- `--prompt `: prompt ID to execute. Required. -- `--prompt-id `: deprecated alias for `--prompt`. -- `--profile `: explicit profile override. -- `--profile-id `: deprecated alias for `--profile`. -- `--input name=path`: input mapping (repeatable, comma-separated accepted). -- `--var name=value`: template variable mapping (repeatable, comma-separated accepted). -- `--out `: write artifact body to file instead of stdout. +- `--profile `: execution profile override. If omitted, the prompt `default_profile` is used. +- `--var name=value`: template variable mapping. Repeat or use comma-separated mappings. +- `--out `: write generated artifact body to a file instead of stdout. - `--llm-base-url `: runtime endpoint override. - `--model `: runtime model override. -- `--api-key-env `: runtime API key environment-variable name override. +- `--api-key-env `: runtime API-key environment variable name override. - `--temperature `: runtime temperature override. - `--max-tokens `: runtime max tokens override. - `--top-p `: runtime top-p override. -- `--timeout `: runtime timeout override (Go duration syntax, for example `30s`, `2m`). +- `--timeout `: runtime timeout override using Go duration syntax, such as `30s` or `2m`. -Numeric runtime override flags are presence-aware: +Deprecated aliases: -- omitted numeric flags preserve the selected profile/default value -- explicit zero values override the selected profile/default value (`--temperature 0`, `--max-tokens 0`, `--top-p 0`, `--timeout 0s`) +- `--prompt-id `: alias for `--prompt`. +- `--profile-id `: alias for `--profile`. + +Runtime override notes: + +- Omitted numeric override flags preserve the selected profile/default value. +- Explicit zero values override the selected profile/default value. +- `--timeout 0s` disables the outbound HTTP client timeout for that request. +- There is no raw API-key flag; use `--api-key-env`. ### `scriptorium render` -- Supports the same flags as `run`, except: - - no `--schema-dir` flag. -- Adds: - - `--format text|json`: prepared-run output format. +```bash +scriptorium render [flags] +``` + +Required through flags or config: + +- `--prompt-dir `: prompt definition directory. + +Required as flags: + +- `--prompt `: prompt ID to render. +- `--input name=path`: input file mapping. Repeat or use comma-separated mappings. + +Optional flags: + +- `--config `: application config file. +- `--prompt-dir `: prompt definition directory. +- `--profile-dir `: custom profile definition directory. +- `--profile `: execution profile override. +- `--var name=value`: template variable mapping. Repeat or use comma-separated mappings. +- `--out `: write prepared-run output to a file instead of stdout. +- `--llm-base-url `: runtime endpoint override for the prepared request. +- `--model `: runtime model override for the prepared request. +- `--api-key-env `: runtime API-key environment variable name override. +- `--temperature `: runtime temperature override. +- `--max-tokens `: runtime max tokens override. +- `--top-p `: runtime top-p override. +- `--timeout `: runtime timeout override using Go duration syntax. +- `--format text|json`: prepared-run output format. Defaults to config `defaults.render_format`, then `text`. + +Deprecated aliases: + +- `--prompt-id `: alias for `--prompt`. +- `--profile-id `: alias for `--profile`. Notes: -- `render` still resolves profile and runtime settings. -- `render` still validates that `api_key_env` exists if the selected profile or overrides require it. + +- `render` resolves profiles, loads schemas for `json_schema` prompts, and validates `api_key_env`. +- `render` does not accept `--schema-dir`; use config `schema_dir` for render-time schema lookup. +- `render` does not call the LLM. ### `scriptorium serve` -- `--config `: app config file path. +```bash +scriptorium serve [flags] +``` + +Required through flags or config: + +- `--prompt-dir `: prompt definition directory. + +Optional flags: + +- `--config `: application config file. - `--addr `: HTTP listen address. - `--prompt-dir `: prompt definition directory. - `--profile-dir `: custom profile definition directory. - `--schema-dir `: schema base directory for `json_schema` validation. - `--artifact-root `: base directory for HTTP `file` input references. -- `--max-request-bytes `: maximum HTTP request body bytes; `0` disables this limit. -- `--max-artifact-bytes `: maximum HTTP file artifact bytes; `0` disables this limit. -- `--max-response-bytes `: maximum encoded HTTP response body bytes; `0` disables this limit. +- `--max-request-bytes `: maximum HTTP request body bytes; `0` disables the limit. +- `--max-artifact-bytes `: maximum HTTP file artifact bytes; `0` disables the limit. +- `--max-response-bytes `: maximum encoded HTTP response body bytes; `0` disables the limit. Notes: + - `serve` does not accept runtime model override flags such as `--model` or `--llm-base-url`. -- HTTP `file` input references are rejected unless an artifact root is configured through `server.artifact_root` or `--artifact-root`. -- `--artifact-root` and the HTTP size-limit flags affect only `serve`; `run` and `render` file input paths are unchanged. +- HTTP request fields and error codes are documented in the [HTTP API reference](api.md). +- HTTP `file` input references are rejected unless an artifact root is configured. +- HTTP size-limit flags affect only `serve`. ## Input And Variable Syntax - `--input name=path` maps prompt input names to local file paths. -- `--var name=value` maps template variable names to values. -- If a prompt defines `session_id: "{{ .session_id }}"`, pass the OpenRouter sticky-routing value with `--var session_id=`. +- `--var name=value` maps prompt template variables to string values. - Both flags can be repeated. -- Both flags also support comma-separated batches, for example: - - `--input transcript=./t.md,glossary=./g.yml` - - `--var session_id=42,session_date=2026-05-04` +- Both flags also accept comma-separated mappings, such as `--input transcript=./t.md,glossary=./g.yml`. +- Values may contain `=` after the first separator, such as `--var note=a=b=c`. +- Empty names and empty values are rejected. + +CLI `run` and `render` convert every `--input` mapping to a `file` artifact +reference. HTTP also supports `inline` input references; see [HTTP API +reference](api.md). ## Output Behavior `run`: + - Writes generated artifact content to stdout by default. - Writes generated artifact content to `--out` when provided. -- Prints run summary metadata to stderr on success. -- Appends `cached_tokens= cache_write_tokens=` to the summary only when the provider reports non-zero cache usage. +- Prints a success summary to stderr. - Prints errors to stderr on failure. `render`: + - Writes prepared-run output to stdout by default. - Writes prepared-run output to `--out` when provided. -- Does not print a success summary line. +- Does not print a success summary. `serve`: + - Logs startup and server errors to stderr. ## Exit Codes - `0`: success. -- `1`: runtime/parse/config/load/render/generation/output-write error. -- `2`: `run` completed, output was generated, but validation status is `failed`. - -When `run` exits `2`, output may already be written to stdout or `--out`. +- `1`: parse, config, load, render, generation, output-write, or runtime error. +- `2`: `run` completed and wrote output, but validation status is `failed`. ## Common Workflows -Render prompt inputs and template variables as JSON: +Render prompt inputs and variables as JSON: ```bash go run ./cmd/scriptorium render \ @@ -142,7 +210,7 @@ go run ./cmd/scriptorium render \ --format json ``` -Run a prompt with profile override and file output: +Run a prompt with an explicit profile and file output: ```bash go run ./cmd/scriptorium run \ @@ -154,12 +222,12 @@ go run ./cmd/scriptorium run \ --out ./summary.md ``` -Start the HTTP server with explicit config: +Start the HTTP server with example config: ```bash go run ./cmd/scriptorium serve --config ./examples/config.yml ``` -Copyable example script: +Copyable maintained script: - `examples/render-markdown-summary.sh` diff --git a/docs/config.md b/docs/config.md index 820c95c..a6104f4 100644 --- a/docs/config.md +++ b/docs/config.md @@ -2,30 +2,32 @@ ## Config Discovery And Precedence -Application settings are loaded in this order: +Application settings are resolved in this order: -1. Built-in defaults +1. built-in defaults 2. `config.yml` values 3. CLI overrides -When `--config` is not provided, Scriptorium searches for config files in this order: +When `--config` is omitted, Scriptorium searches: 1. `/usr/local/etc/scriptorium/config.yml` 2. `/etc/scriptorium/config.yml` -If neither file exists, Scriptorium continues with built-in defaults. +If neither file exists, Scriptorium uses built-in defaults. When +`--config ` is provided, that file must exist and decode successfully. -When `--config ` is provided, that file is required. - -## Minimal App Config +## Minimal Working Config ```yaml prompt_dir: ./examples/prompts ``` -This is enough to use `run` and `render` when prompts select built-in profiles. +This is enough for `run` and `render` when selected prompts use built-in +profiles. Set `profile_dir` when prompts or requests use custom profiles. -## Production-Oriented App Config +The maintained repository example is `examples/config.yml`. + +## Production-Oriented Config ```yaml prompt_dir: /opt/scriptorium/prompts @@ -43,57 +45,48 @@ defaults: render_format: text ``` -## App Config File (`config.yml`) +The maintained full example is `examples/config.full.yml`. + +## App Config Reference 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`. -- `server.artifact_root` (optional): base directory for HTTP `file` input references. -- `server.max_request_bytes` (optional): maximum HTTP request body size. `0` disables this limit. -- `server.max_artifact_bytes` (optional): maximum HTTP `file` input artifact size. `0` disables this limit. -- `server.max_response_bytes` (optional): maximum encoded HTTP response body size. `0` disables this limit. -- `defaults.render_format` (optional): default `render` output format (`text` or `json`). +| Field | Default | Description | +| --- | --- | --- | +| `prompt_dir` | unset | Directory containing prompt definition YAML files. Required effectively by `run`, `render`, and `serve`. | +| `profile_dir` | unset | Directory containing custom profile YAML files. Built-in profiles remain available when unset. | +| `schema_dir` | `.` | Base directory for relative JSON Schema paths. | +| `server` | `{}` | HTTP service settings used by `serve`. | +| `defaults` | `{}` | Adapter defaults. | -Built-in defaults: +`server` fields: -- `schema_dir`: `.` -- `server.addr`: `:8080` -- `server.artifact_root`: unset; HTTP `file` input references are rejected until configured. -- `server.max_request_bytes`: `16777216` (16 MiB) -- `server.max_artifact_bytes`: `16777216` (16 MiB) -- `server.max_response_bytes`: `16777216` (16 MiB) -- `defaults.render_format`: `text` +| Field | Default | Description | +| --- | --- | --- | +| `server.addr` | `:8080` | Listen address for `serve`. | +| `server.artifact_root` | unset | Base directory for HTTP `file` input references. Without it, HTTP file refs are rejected. | +| `server.max_request_bytes` | `16777216` | Maximum encoded HTTP request body bytes. `0` disables the limit. | +| `server.max_artifact_bytes` | `16777216` | Maximum HTTP file artifact bytes. `0` disables the limit. | +| `server.max_response_bytes` | `16777216` | Maximum encoded HTTP response bytes. `0` disables the limit. | -Validation behavior: +`defaults` fields: -- Config decoding is strict; unknown YAML fields are rejected. -- HTTP size limit values must be greater than or equal to `0`. -- Raw API key fields are not supported in `config.yml`. +| Field | Default | Description | +| --- | --- | --- | +| `defaults.render_format` | `text` | Default `render` output format: `text` or `json`. | -HTTP artifact root behavior: +Config rules: -- `server.artifact_root` applies only to `serve`. -- HTTP `inline` input references work without an artifact root. -- HTTP `file` input references are resolved against `server.artifact_root` with lexical path checks. -- Relative traversal and absolute paths that are lexically outside the root are rejected. -- Symlinks inside the root are followed by the operating system, including symlinks that point outside the root. Do not make the artifact root writable by untrusted users. -- CLI `run` and `render` file inputs keep their normal direct filesystem path behavior. - -HTTP size-limit behavior: - -- The request limit covers the encoded JSON request body, including inline input bodies. -- The artifact limit covers HTTP `file` input artifacts read through `serve`. -- The response limit covers the final encoded JSON response, including generated artifact bodies and `raw_model_output` when requested. -- Limits apply only to HTTP `serve`; CLI `run` and `render` keep direct filesystem behavior. +- YAML decoding is strict; unknown fields are rejected. +- HTTP size limits must be greater than or equal to `0`. +- Empty string config values are ignored. +- Raw API key fields are not supported in app config. ## 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`. +Prompt definitions are YAML files anywhere under `prompt_dir`. Nested +directories are organizational; callers select prompts by YAML `id`, not file +path. Example: @@ -126,84 +119,76 @@ output: repair_attempts: 0 ``` -Field reference: +Prompt fields: -- `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. +| Field | Required | Description | +| --- | --- | --- | +| `id` | yes | Prompt identifier used by `--prompt` and HTTP `prompt_id`. | +| `version` | yes | Prompt version. | +| `default_profile` | no | Profile ID used when a request does not provide a profile. | +| `description` | no | Human-readable description. | +| `session_id` | no | Go-template string rendered from request vars and forwarded as provider `session_id` when non-empty. | +| `inputs` | no | Named input declarations. | +| `messages` | yes | Chat message templates. | +| `output` | yes | Output format and validation contract. | `inputs[]` fields: - `name` (required) -- `required` (optional, boolean) +- `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 +- exactly one of `content` or `content_file` +- `cache_control` (optional) Message rules: +- `content_file` resolves relative to the prompt YAML file location. - 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. +- Prompt YAML decoding is strict. +- Duplicate input names are invalid. +- Duplicate prompt IDs are invalid for a requested ID/version. `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. +| Field | Required | Supported values | +| --- | --- | --- | +| `type` | yes | `ephemeral` | +| `ttl` | no | `1h` | -Example cache-controlled message: +`session_id` behavior: -```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": ""}`. +- Rendered with the same variable context as message templates. +- Trimmed and omitted when empty. +- Rejected when longer than 256 Unicode code points. +- CLI callers pass variables with `--var`; HTTP callers use `vars`. `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`. +| Field | Required | Supported values | +| --- | --- | --- | +| `format` | yes | `text`, `markdown`, `json` | +| `validation_mode` | yes | `none`, `basic`, `json`, `json_schema` | +| `schema_path` | only for `json_schema` | Relative to `schema_dir` unless absolute. | +| `repair_attempts` | yes | Integer greater than or equal to `0`. | -Repair behavior boundary: +Repair 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. +- The current CLI and HTTP wiring constructs the runner without a repairer, so normal `run` and `serve` execution does not perform repair attempts. ## Profile Definition Files -Scriptorium includes built-in execution profiles. Custom execution profiles are YAML files anywhere under `profile_dir`, including nested subdirectories. +Execution profiles are YAML files anywhere under `profile_dir`. Nested +directories are organizational; callers select profiles by YAML `id`, not file +path. -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`. +Scriptorium also ships built-in profiles. Custom profiles override built-ins +with the same ID. Example: @@ -220,36 +205,44 @@ service_tier: priority reasoning_effort: medium extra_params: provider_route: primary - provider_options: - retry_budget: 2 ``` -Field reference: +Profile fields: -- `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. +| Field | Required | Description | +| --- | --- | --- | +| `id` | yes | Profile identifier. | +| `endpoint` | yes | OpenAI-compatible base URL including `/v1`. | +| `model` | yes | Provider model name. | +| `temperature` | no | Range `0..2`. | +| `max_tokens` | no | Integer greater than or equal to `0`. | +| `top_p` | no | Range `0..1`. | +| `timeout_seconds` | no | Integer greater than or equal to `0`. | +| `service_tier` | no | Provider-specific request tier. | +| `reasoning_effort` | no | Provider-specific reasoning setting. | +| `api_key_env` | no | Environment variable name containing the API key. | +| `extra_params` | no | JSON-compatible provider-specific top-level request fields. | + +Execution defaults before profile/request overrides: + +| Field | Default | +| --- | --- | +| `temperature` | `0.0` | +| `max_tokens` | `0` | +| `top_p` | `1.0` | +| `timeout_seconds` | `600` | 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. +- Profile YAML decoding is strict. +- Duplicate custom profile IDs are invalid. +- Matching custom and built-in IDs are valid override behavior. - 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`. +- If `api_key_env` is set, the named environment variable must be set before `run`, `render`, or HTTP execution can prepare the request. +- Profile numeric fields merge by non-zero value. Request overrides are presence-aware, so explicit zero values are supported through CLI flags or HTTP model overrides. +- `extra_params` keys must not be empty and must not collide with reserved outbound fields: `model`, `session_id`, `messages`, `temperature`, `max_tokens`, `top_p`, `service_tier`, `reasoning_effort`, or `response_format`. -Built-in profile IDs: +Built-in profile catalog: | Provider | ID | Model | API key env | | --- | --- | --- | --- | @@ -277,56 +270,55 @@ Built-in profile IDs: | openai | `gpt-5-mini` | `openai/gpt-5.4-mini` | `OPENROUTER_API_KEY` | | openai | `gpt-5-nano` | `openai/gpt-5.4-nano` | `OPENROUTER_API_KEY` | -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`. +Schemas are JSON files, typically under `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`. +- Relative `schema_path` values resolve from `schema_dir`. - 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). +- Nested schemas must be referenced by relative path; schemas are not searched recursively by basename. +- Missing or invalid schema documents are runtime validation errors. +- Invalid generated JSON produces validation status `failed`, not a runtime error. -Supported artifact reference types for request inputs are `file` and `inline`. -For HTTP `serve`, `file` references require `server.artifact_root` and must pass -lexical containment checks against that root. CLI `run` and `render` file inputs -are not restricted by `server.artifact_root`. +## Artifact References + +Supported request input artifact reference types are: + +- `file` +- `inline` + +CLI `run` and `render` create `file` references from `--input name=path`. + +HTTP `file` references require `server.artifact_root` or `serve +--artifact-root`. Relative file URIs resolve under that root. Absolute paths +and relative traversal outside the root are rejected by lexical checks. Symlinks +inside the root are followed by the operating system, including symlinks that +point outside the root. + +HTTP `inline` references do not require an artifact root. ## 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. +- Store only environment-variable names in `api_key_env`. +- Do not put raw API keys in config, prompts, profiles, CLI arguments, examples, or HTTP request bodies. ## Maintained Examples -- App config: `examples/config.yml` +- Minimal app config: `examples/config.yml` +- Full app config: `examples/config.full.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 -``` +- Render script: `examples/render-markdown-summary.sh` +- HTTP request-shape example: `examples/http-run.json` ## Integration References +- [CLI reference](cli.md) - [HTTP API reference](api.md) - [Outbound OpenAI-compatible contract](integrations/openai-compatible-chat.md) diff --git a/examples/config.full.yml b/examples/config.full.yml new file mode 100644 index 0000000..0e70e12 --- /dev/null +++ b/examples/config.full.yml @@ -0,0 +1,13 @@ +prompt_dir: ./examples/prompts +profile_dir: ./examples/profiles +schema_dir: ./examples/schemas + +server: + addr: 127.0.0.1:8080 + artifact_root: . + max_request_bytes: 16777216 + max_artifact_bytes: 16777216 + max_response_bytes: 16777216 + +defaults: + render_format: text