From 879cb021b29ec616ac9e40968a671af91dfd8d5f Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Sun, 5 Jul 2026 03:06:39 +0000 Subject: [PATCH] Clarify HTTP operations documentation --- docs/api.md | 282 ++++++++++++++++++------------ docs/operations.md | 185 +++++++++++--------- docs/troubleshooting.md | 376 +++++++++++++++++++--------------------- 3 files changed, 448 insertions(+), 395 deletions(-) diff --git a/docs/api.md b/docs/api.md index 72fc075..6e0c575 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,40 +1,68 @@ # HTTP API Reference -## Scope +This is the canonical public HTTP contract for Scriptorium. -This document is the canonical public HTTP contract for Scriptorium. - -Current scope is only: +Implemented route: - `POST /v1/runs` -For CLI behavior, see the [CLI reference](cli.md). +For CLI behavior, see [CLI reference](cli.md). For config and prompt/profile +file formats, see [Configuration reference](config.md). -## Endpoint +## Base URL And Deployment -- Method: `POST` -- Path: `/v1/runs` -- Content type: JSON request/response +`scriptorium serve` listens on `server.addr` or `serve --addr`. The default is +`:8080`. -Route behavior: +The route path is always: -- unknown path: `404 not_found` -- unsupported method on `/v1/runs`: `405 method_not_allowed` +```text +/v1/runs +``` -Copyable request example file: +The HTTP adapter has no built-in authentication or authorization. Deploy it +behind trusted network and authentication controls. -- `examples/http-run.json` +## Media Types -## Request Body +- Request body: JSON object. +- Response body: JSON object. +- Response `Content-Type`: `application/json`. + +Requests are decoded as JSON regardless of the request `Content-Type` header. +There are no shared query parameters. + +## Request Limits + +HTTP limits are configured through `server.*` config fields or `serve` flags: + +- `server.max_request_bytes`: encoded JSON request body limit, including inline input bodies. +- `server.max_artifact_bytes`: file artifact limit for HTTP `file` input references. +- `server.max_response_bytes`: encoded JSON response limit, including artifact body and optional raw output. + +Each limit defaults to `16777216` bytes. `0` disables that limit. + +## `POST /v1/runs` + +Runs one prompt request and returns the generated artifact, validation result, +and metadata. + +### Request Body ```json { - "prompt_id": "generic.structured_events", - "profile_id": "local-quality", + "prompt_id": "generic.markdown_summary", + "profile_id": "local-fast", "prompt_version": "1.0.0", "inputs": { - "transcript": {"type": "file", "uri": "./examples/fixtures/transcript.md"}, - "glossary": {"type": "inline", "body": "party:\n - Rin"} + "transcript": { + "type": "file", + "uri": "./examples/fixtures/transcript.md" + }, + "glossary": { + "type": "inline", + "body": "party:\n - Rin" + } }, "vars": { "session_date": "2026-05-04" @@ -42,112 +70,120 @@ Copyable request example file: "model": { "endpoint": "http://localhost:8000/v1", "model": "gpt-4o-mini", - "temperature": 0.0, + "temperature": 0, "max_tokens": 800, - "top_p": 1.0, + "top_p": 1, "timeout_seconds": 120, "service_tier": "priority", "reasoning_effort": "medium", "api_key_env": "SCRIPTORIUM_API_KEY", "extra_params": { - "route": "primary", - "provider_options": { - "retry_budget": 2 - } + "provider_option": "enabled" } }, "include_raw_output": false } ``` -Required fields: +Request fields: -- `prompt_id` -- `inputs` (must contain at least one named input) +| Field | Required | Description | +| --- | --- | --- | +| `prompt_id` | yes | Prompt ID. Must not be blank. | +| `prompt_version` | no | Prompt version filter. | +| `profile_id` | no | Execution profile ID. If omitted, the prompt must define `default_profile`. | +| `inputs` | yes | Object mapping prompt input names to input references. Must contain at least one entry. | +| `vars` | no | Object mapping template variable names to string values. | +| `model` | no | Runtime model override object. | +| `include_raw_output` | no | When `true`, include `raw_model_output` in the response. | -Input reference types currently supported by runtime artifact loading: +Input reference fields: -- `file` -- `inline` +| Field | Required | Description | +| --- | --- | --- | +| `type` | yes | `file` or `inline`. | +| `uri` | for `file` | File URI/path. | +| `body` | for `inline` | Inline artifact body. | -HTTP `file` references require `server.artifact_root` or `serve --artifact-root`. -Relative file URIs resolve against that root. Absolute file URIs are accepted -only when they are lexically inside the root. Requests that escape the root by -lexical traversal, including `..` traversal and absolute paths outside the root, -return `400 artifact_not_allowed`. Symlinks inside the root are followed by the -operating system, including symlinks that point outside the root. The artifact -root must not be writable by untrusted users. `inline` references do not require -an artifact root. -HTTP file artifacts above the configured artifact limit return -`413 artifact_too_large`. Inline bodies are bounded by the request body limit. +HTTP `file` references require `server.artifact_root` or `serve +--artifact-root`. Relative file URIs resolve against that root. Absolute file +URIs are accepted only when lexically inside the root. Relative traversal and +absolute paths outside the root return `400 artifact_not_allowed`. -Model override notes: +The containment check is lexical and does not resolve symlinks. Symlinks inside +the artifact root are followed by the operating system, including symlinks that +point outside the root. Keep the artifact root narrow and not writable by +untrusted users. -- Numeric model override fields distinguish omitted values from explicit zero values. For example, omitting `temperature` preserves the selected profile/default value, while `"temperature": 0` explicitly sets the effective temperature to zero. -- `extra_params` accepts JSON-compatible values: strings, numbers, booleans, objects, and arrays. -- `extra_params` are passed through effective model metadata and flattened into top-level provider request fields by the OpenAI-compatible client. -- `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`. -- Raw API-key values are not accepted. Use `api_key_env` to name an environment variable. +Model override fields: -## Strict JSON Rules +| Field | Description | +| --- | --- | +| `endpoint` | Runtime endpoint override. | +| `model` | Runtime model override. | +| `temperature` | Number in range `0..2`. Explicit `0` is an override. | +| `max_tokens` | Integer greater than or equal to `0`. Explicit `0` is an override. | +| `top_p` | Number in range `0..1`. Explicit `0` is an override. | +| `timeout_seconds` | Integer greater than or equal to `0`. Explicit `0` disables the outbound client timeout. | +| `service_tier` | Provider-specific request tier. | +| `reasoning_effort` | Provider-specific reasoning setting. | +| `api_key_env` | Name of an environment variable containing the API key. | +| `extra_params` | JSON-compatible provider-specific top-level request fields. | -Request decoding uses strict JSON field checks: +Raw API-key values are not accepted in HTTP payloads. A field such as +`api_key` is rejected as unknown JSON. -- unknown request fields are rejected with `400 invalid_json` -- unknown `model` fields are rejected with `400 invalid_json` -- raw API-key payload fields such as `api_key` are rejected as unknown fields -- request bodies above the configured request limit are rejected with `413 request_too_large` -- trailing JSON tokens after the request object are rejected with `400 invalid_json` +`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`. -## Success Response +### Strict JSON Rules + +Request decoding is strict: + +- malformed JSON returns `400 invalid_json` +- unknown request fields return `400 invalid_json` +- unknown `inputs` item fields return `400 invalid_json` +- unknown `model` fields return `400 invalid_json` +- trailing JSON tokens after the request object return `400 invalid_json` +- request bodies above the configured limit return `413 request_too_large` + +### Success Response Status: `200 OK` -Response shape: - ```json { "artifact": { "name": "output", - "content_type": "application/json", - "body": "{\"summary\":\"...\"}", - "uri": "", - "size": 123, + "content_type": "text/markdown", + "body": "Generated content", + "size": 17, "hash": "..." }, "validation": { "status": "passed", - "mode": "json_schema", - "errors": [], - "schema_path": "structured_events.schema.json", + "mode": "basic", "repair_attempts": 0, "is_valid": true }, "metadata": { "run_id": "...", - "prompt_id": "generic.structured_events", + "prompt_id": "generic.markdown_summary", "prompt_version": "1.0.0", "prompt_hash": "...", "rendered_prompt_hash": "...", - "selected_profile_id": "local-quality", + "selected_profile_id": "local-fast", "model_name": "gpt-4o-mini", "endpoint": "http://localhost:8000/v1", "model_params": { "endpoint": "http://localhost:8000/v1", "model": "gpt-4o-mini", - "temperature": 0, - "max_tokens": 800, + "temperature": 0.2, + "max_tokens": 500, "top_p": 1, - "timeout_seconds": 120, - "service_tier": "priority", - "reasoning_effort": "medium", - "api_key_env": "SCRIPTORIUM_API_KEY", - "extra_params": { - "route": "primary", - "provider_options": { - "retry_budget": 2 - } - } + "timeout_seconds": 90 }, "input_hashes": { "transcript": "..." @@ -162,30 +198,46 @@ Response shape: "start_time": "2026-05-04T12:00:00Z", "end_time": "2026-05-04T12:00:01Z", "duration_ms": 1000, - "validation_mode": "json_schema", + "validation_mode": "basic", "validation_status": "passed", "repair_attempts_used": 0 } } ``` -`raw_model_output` is omitted by default. +Response fields: -`metadata.usage.cached_tokens` and `metadata.usage.cache_write_tokens` are always present as numbers. They are `0` when the provider omits compatible cache usage fields or reports no cache activity. +- `artifact`: generated output artifact. +- `validation`: validation result for the generated artifact. +- `metadata`: run and effective runtime metadata. +- `raw_model_output`: omitted unless `include_raw_output` is `true`. -To include it, send: +`artifact.uri` is omitted when empty. `validation.errors` and +`validation.schema_path` are omitted when empty. `model_params.service_tier`, +`model_params.reasoning_effort`, `model_params.api_key_env`, and +`model_params.extra_params` are omitted when empty. -- `"include_raw_output": true` +`metadata.usage.cached_tokens` and `metadata.usage.cache_write_tokens` are +always present as numbers. They are `0` when the provider omits compatible cache +usage fields or reports no cache activity. -## Validation Failure Behavior +### Validation Failure Response -Validation content failures do not map to HTTP error status. +Generated-content validation failures still return `200 OK`. -Behavior: +```json +{ + "validation": { + "status": "failed", + "mode": "json", + "errors": ["invalid JSON: ..."], + "repair_attempts": 0, + "is_valid": false + } +} +``` -- status remains `200 OK` -- `validation.status` is `failed` -- validation errors are returned in `validation.errors` +The response still includes `artifact` and `metadata`. ## Error Responses @@ -200,28 +252,38 @@ Error body shape: } ``` -Current error mapping (non-exhaustive): +Current status/code mapping: -- `400 invalid_json`: malformed JSON or unknown JSON fields -- `400 invalid_request`: missing/invalid request fields -- `400 profile_required`: no explicit `profile_id` and prompt has no `default_profile` -- `400 prompt_load_failed`: prompt definition invalid/unloadable -- `400 profile_load_failed`: profile invalid/unloadable -- `400 artifact_not_allowed`: file input artifact is outside the configured artifact root or file refs are not enabled -- `400 artifact_read_failed`: input artifact loading failed -- `400 prompt_render_failed`: template render failed -- `400 api_key_env_missing`: named API-key environment variable is missing -- `413 request_too_large`: request body exceeds the configured request limit -- `413 artifact_too_large`: HTTP file input artifact exceeds the configured artifact limit -- `413 response_too_large`: encoded JSON response exceeds the configured response limit -- `404 prompt_not_found` -- `404 profile_not_found` -- `502 llm_failed`: outbound model request failed -- `500 validation_runtime_failed`: validator runtime/schema-load failure -- `500 internal_error` +| Status | Code | Meaning | +| --- | --- | --- | +| `400` | `invalid_json` | Malformed JSON, unknown JSON field, or trailing JSON token. | +| `400` | `invalid_request` | Missing/invalid request fields or invalid runtime overrides. | +| `400` | `profile_required` | No `profile_id` and prompt has no `default_profile`. | +| `400` | `prompt_load_failed` | Prompt definition YAML/contract failed to load. | +| `400` | `profile_load_failed` | Profile YAML/contract failed to load, including raw `api_key`. | +| `400` | `artifact_not_allowed` | HTTP file refs are disabled or requested path is outside artifact root. | +| `400` | `artifact_read_failed` | Input artifact could not be read or input ref was unsupported/invalid. | +| `400` | `prompt_render_failed` | Prompt template rendering failed. | +| `400` | `api_key_env_missing` | Selected `api_key_env` variable is unset or empty. | +| `404` | `not_found` | Route path is unknown. | +| `404` | `prompt_not_found` | Prompt ID/version was not found. | +| `404` | `profile_not_found` | Profile ID was not found. | +| `405` | `method_not_allowed` | Method is not `POST` on `/v1/runs`. | +| `413` | `request_too_large` | Encoded JSON request body exceeds configured request limit. | +| `413` | `artifact_too_large` | HTTP file input artifact exceeds configured artifact limit. | +| `413` | `response_too_large` | Encoded JSON response exceeds configured response limit. | +| `500` | `validation_runtime_failed` | Validator runtime/schema loading failed. | +| `500` | `internal_error` | Unclassified server error. | +| `502` | `llm_failed` | Outbound model request failed. | -## Security And Deployment Note +HTTP error messages are intentionally concise and do not include sensitive +internal causes. -The HTTP adapter has no built-in authentication or authorization. +## Retry And Idempotency -Deploy behind trusted controls (for example authenticated gateway/reverse proxy and network boundaries). +Scriptorium does not provide idempotency keys, pagination, caching headers, or +rate limiting. + +Clients may retry transport failures or `5xx` responses when their surrounding +workflow can tolerate another model call. A retry can generate different output +and incur another provider request. diff --git a/docs/operations.md b/docs/operations.md index 7e6a100..7217682 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -2,139 +2,154 @@ ## Scope -This document covers day-to-day operation of the CLI and HTTP service for currently implemented behavior. - -For command syntax, see [CLI reference](cli.md). For file formats and defaults, see [Configuration reference](config.md). +This guide covers operating the implemented CLI commands and HTTP service. It +does not replace the [CLI reference](cli.md), [Configuration reference](config.md), +or [HTTP API reference](api.md). ## Operational Model -Scriptorium executes one request at a time per CLI invocation or HTTP request. +Scriptorium executes one prompt request per CLI invocation or HTTP request. Important boundaries: - No durable run state is stored. -- No built-in resume, checkpoint, archive, or backup workflow exists. -- Recovery is rerun-based: fix inputs/config, then rerun. +- No manifest, archive, checkpoint, or built-in backup workflow is written. +- No built-in resume behavior exists. +- Recovery is rerun-based: correct inputs, config, or environment, then run again. -## Filesystem Layout And Config +## Filesystem Layout -Scriptorium depends on: +Operational deployments usually provide: -- prompt definition files (`prompt_dir`) -- execution profile files (`profile_dir`) -- optional JSON schemas (`schema_dir`) +- `prompt_dir`: prompt definition YAML files and adjacent `content_file` templates. +- `profile_dir`: optional custom profile YAML files. +- `schema_dir`: optional JSON Schema files. +- `server.artifact_root`: optional HTTP file-input root for `serve`. -Config discovery order when `--config` is omitted: - -1. `/usr/local/etc/scriptorium/config.yml` -2. `/etc/scriptorium/config.yml` - -If neither exists, built-in defaults are used. If `--config ` is provided, that file must exist and parse successfully. - -Built-in defaults relevant to operations: - -- `schema_dir: .` -- `server.addr: :8080` -- `server.artifact_root`: unset; HTTP `file` input references are rejected until configured -- `server.max_request_bytes: 16777216` -- `server.max_artifact_bytes: 16777216` -- `server.max_response_bytes: 16777216` -- `defaults.render_format: text` +Keep these directories readable by the Scriptorium process. Keep +`server.artifact_root` narrow and not writable by untrusted users. ## Normal CLI Workflow -Use `render` first when you need to verify prompt resolution and runtime settings without calling a model. +Use `render` before `run` when changing prompt/profile/input wiring: -Use `run` for generation. +```bash +go run ./cmd/scriptorium render \ + --config ./examples/config.yml \ + --prompt generic.markdown_summary \ + --input transcript=./examples/fixtures/transcript.md \ + --input glossary=./examples/fixtures/glossary.yml \ + --format json +``` -Typical sequence: +Use `run` for generation after preflight: -1. Confirm prompt/profile directories resolve through config or flags. -2. Confirm required input files exist and map to prompt input names. -3. Confirm required API-key environment variables are set. -4. Confirm the selected profile's model endpoint is reachable from the process environment. -5. Run `render` for preflight when changing prompt/profile/input wiring. -6. Run `run` for actual generation. +```bash +go run ./cmd/scriptorium run \ + --config ./examples/config.yml \ + --prompt generic.markdown_summary \ + --input transcript=./examples/fixtures/transcript.md \ + --input glossary=./examples/fixtures/glossary.yml \ + --out ./summary.md +``` -## Secrets Handling +Before production runs, confirm: -Raw API keys are not accepted in config files, profile files as `api_key`, CLI flags, or HTTP request bodies. - -Operational pattern: - -- Set environment variables that hold secret values. -- Set profile `api_key_env` (or runtime override `api_key_env`) to the environment variable name. -- Keep process environments scoped to only required variables. +- the effective config path is the intended one; +- prompt/profile/schema directories are readable; +- input file paths exist and match prompt input names; +- required API-key environment variables are set; +- the selected model endpoint is reachable from the process environment. ## HTTP Service Operation -Start service with: +Start the service with: ```bash go run ./cmd/scriptorium serve --config ./examples/config.yml ``` -Current inbound API behavior: +The implemented HTTP route is `POST /v1/runs`; request and response fields are +defined in the [HTTP API reference](api.md). -- Route: `POST /v1/runs` -- JSON request parsing rejects unknown fields. -- Validation content failures still return `200 OK` with `validation.status: "failed"`. -- `inline` input references work without filesystem configuration. -- `file` input references require `server.artifact_root` or `serve --artifact-root`; relative traversal and absolute paths that are lexically outside that root are rejected. -- Request bodies, HTTP file input artifacts, and encoded JSON responses are limited by `server.max_request_bytes`, `server.max_artifact_bytes`, and `server.max_response_bytes`. +HTTP service notes: -Security caveat: +- Unknown JSON fields are rejected. +- `inline` input references work without an artifact root. +- `file` input references require `server.artifact_root` or `serve --artifact-root`. +- Request bodies, HTTP file input artifacts, and encoded JSON responses are size-limited. +- Validation content failures return `200 OK` with `validation.status: "failed"`. + +Security boundary: - `serve` has no built-in authentication or authorization. -- Deploy only behind trusted controls (private network boundary, authenticated reverse proxy, API gateway, or equivalent). -- Keep the HTTP artifact root as narrow as practical and do not make it writable by untrusted users. Symlinks inside the root are followed by the operating system, including symlinks that point outside the root. +- Put it behind trusted controls such as a private network, authenticated reverse proxy, or API gateway. +- Do not expose an artifact root containing unrelated sensitive files. +- Symlinks inside the artifact root are followed by the operating system. -Sizing guidance: +## Secrets Handling -- Keep limits at the defaults unless a deployment has a measured need for larger prompt inputs or outputs. -- Prefer `inline` inputs for small payloads and HTTP `file` inputs for larger local artifacts inside a controlled artifact root. -- Increase the response limit when prompts intentionally return large generated artifacts or when clients request `include_raw_output`. -- Set a limit to `0` only for trusted deployments where another layer enforces request and response size. +Raw API keys are not accepted in app config, profiles, CLI flags, or HTTP +request bodies. + +Use this pattern: + +1. Set an environment variable containing the secret value. +2. Store only the variable name in profile `api_key_env` or request override `api_key_env`. +3. Scope the process environment to the minimum required variables. ## Output, Logs, And Exit Codes -`run` command: +`run`: -- Generated artifact body goes to stdout by default. -- `--out` writes generated artifact to a file. -- Summary metadata line is written to stderr on success. -- Exit code `2` means generation completed but validation failed. +- stdout: generated artifact body unless `--out` is used. +- stderr: summary on success, errors on failure. +- exit `2`: generation completed and output was written, but validation failed. -`render` command: +`render`: -- Prepared-run output goes to stdout by default. -- `--out` writes prepared-run output to a file. -- Exit code is `0` on success and `1` on failure. +- stdout: prepared-run output unless `--out` is used. +- stderr: errors. +- exit `0` on success, `1` on failure. -`serve` command: +`serve`: -- Startup and server errors are written to stderr. +- stderr: startup and server errors. +- HTTP response body: JSON success or error envelope. -## Validation Behavior In Operations +## Validation Behavior -Validation modes (`none`, `basic`, `json`, `json_schema`) are defined by prompt output contract. +Prompt `output.validation_mode` controls validation: -Operational interpretation: +- `none`: skipped. +- `basic`: output body must not be empty. +- `json`: output body must parse as JSON. +- `json_schema`: output body must parse as JSON and satisfy the configured schema. -- Validation runtime errors are hard failures (`run` exit `1`; HTTP error response). -- Validation content failures are soft failures (`run` exit `2`; HTTP `200` with failed status). +Runtime/schema failures are hard failures (`run` exit `1`, HTTP error). +Generated-content validation failures are soft failures (`run` exit `2`, HTTP +`200 OK` with failed validation status). -A failed validation run can still produce output. Decide whether to keep or discard that output in your surrounding workflow. +## Size Limits -## Safe Recovery Steps +Defaults are documented in [Configuration reference](config.md). Operationally: -For failed runs or requests: +- Keep default HTTP limits unless larger payloads are measured and expected. +- Prefer `inline` HTTP inputs for small payloads. +- Prefer `file` HTTP inputs for larger local artifacts under a controlled artifact root. +- Increase `server.max_response_bytes` when generated artifacts or requested raw output are expected to be large. +- Use `0` only when another trusted layer enforces size limits. -1. Capture stderr output or HTTP error code/message. -2. Confirm config path and directory settings. -3. Verify prompt/profile IDs and input mappings. -4. Verify API-key environment-variable presence when required. -5. Reproduce with `render --format json` when prompt/profile/input resolution is uncertain. +## Safe Recovery + +For failed CLI commands or HTTP requests: + +1. Capture stderr or the HTTP error `code` and `message`. +2. Confirm config path and effective directory settings. +3. Verify prompt ID, profile ID, schema path, and input mappings. +4. Verify required API-key environment variables. +5. Reproduce with `render --format json` when pre-LLM resolution is uncertain. 6. Rerun after correction. -Because Scriptorium does not persist run state, rerun is the canonical recovery path. +Because Scriptorium does not persist run state, rerun is the supported recovery +path. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index d37a73a..17942c1 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -1,19 +1,25 @@ # Troubleshooting -This guide lists recurring implemented failure modes and safe fixes. +This guide lists common implemented failure modes and safe fixes. -For command syntax, see [CLI reference](cli.md). For configuration and file formats, see [Configuration reference](config.md). For operational behavior, see [Operations guide](operations.md). +Canonical references: -## Missing Or Invalid Config File +- [CLI reference](cli.md) +- [Configuration reference](config.md) +- [HTTP API reference](api.md) +- [Operations guide](operations.md) + +## Missing Or Invalid Config Symptom: -- CLI errors such as `application config error: config file not found` or `invalid config YAML`. +- CLI error includes `application config error`, `config file not found`, `invalid config YAML`, or `invalid config`. Likely cause: - `--config` points to a missing file. -- Config YAML has syntax errors or unknown fields. +- YAML syntax is invalid. +- Config contains unknown fields or negative HTTP size limits. Diagnostic step: @@ -23,40 +29,34 @@ go run ./cmd/scriptorium render --config /path/to/config.yml --prompt generic.ma Safe fix: -- Correct file path. -- Remove unknown fields. +- Correct the config path. - Fix YAML syntax. -- Keep secrets out of config. +- Remove unknown fields. +- Keep raw secrets out of config. -Relevant links: +Relevant links: [Configuration reference](config.md), [CLI reference](cli.md) -- [Configuration reference](config.md) -- [CLI reference](cli.md) - -## Missing Prompt Directory Settings +## Missing Prompt Directory Symptom: -- CLI parse errors saying prompt directory is required. +- CLI parse error says the prompt directory is required. Likely cause: -- Neither CLI flags nor config provide an effective `prompt_dir`. +- Neither config nor CLI flags provide an effective `prompt_dir`. Diagnostic step: -- Run the failing command with explicit `--prompt-dir` once to verify. +- Re-run once with explicit `--prompt-dir`. Safe fix: -- Set `prompt_dir` in config, or always pass `--prompt-dir`. +- Set `prompt_dir` in config or pass `--prompt-dir`. -Relevant links: +Relevant links: [Configuration reference](config.md), [CLI reference](cli.md) -- [Configuration reference](config.md) -- [CLI reference](cli.md) - -## Unknown Or Unsupported Flags +## Unknown Flags Symptom: @@ -64,33 +64,33 @@ Symptom: Likely cause: -- Typo or command mismatch (for example, `serve` with runtime model override flags). +- Typo. +- Flag is valid for another command. +- `serve` was given runtime model override flags. Diagnostic step: -- Compare command against the command-specific flag list. +- Compare the command with the command-specific flag list. Safe fix: - Remove unsupported flags. -- Use `run`/`render` for runtime model overrides. +- Use `run` or `render` for runtime model overrides. -Relevant links: +Relevant links: [CLI reference](cli.md) -- [CLI reference](cli.md) - -## Prompt Definition Load Failures +## Prompt Load Failures Symptom: -- CLI run/render error from prompt loading. -- HTTP `404 prompt_not_found` or `400 prompt_load_failed`. +- CLI run/render fails during prompt loading. +- HTTP returns `404 prompt_not_found` or `400 prompt_load_failed`. Likely cause: -- Prompt ID not found. -- Invalid prompt YAML. -- Invalid prompt contract (for example bad validation mode, message content/content_file rule violation, missing schema path for `json_schema`). +- Prompt ID/version does not exist. +- Prompt YAML is invalid or has unknown fields. +- Prompt contract is invalid, such as missing messages, invalid output mode, bad `content_file`, or missing `schema_path` for `json_schema`. Diagnostic step: @@ -100,28 +100,25 @@ go run ./cmd/scriptorium render --config ./examples/config.yml --prompt