# scriptorium Scriptorium is a generic prompt-profile execution engine written in Go. Given named input artifacts and a prompt profile, Scriptorium: 1. Loads the profile. 2. Resolves input artifact references. 3. Renders prompt messages from templates. 4. Calls an OpenAI-compatible LLM endpoint. 5. Validates output if configured. 6. Optionally performs bounded structured-output repair. 7. Returns a generated artifact plus run metadata. ## Where Scriptorium Fits Scriptorium is not an orchestrator. In the D&D workflow: - Narratio orchestrates the full pipeline. - WhisperX transcribes audio. - Seriatim merges transcripts. - Audita polishes transcripts. - Scriptorium generates final artifacts from prepared inputs. D&D-specific behavior belongs in profiles, schemas, fixtures, and caller inputs, not in core Go logic. ## Core Concepts - Prompt profile: YAML config that defines templates, model defaults, output format, and validation behavior. - Named inputs: logical input names (for example `transcript`, `glossary`) mapped to artifact references. - Artifact refs: currently `file` and `inline` are supported by readers used in v1 flows. - Template variables: key/value vars provided at run time and accessed in templates as `{{.var_name}}`. - Model target: endpoint/model and generation parameters (`temperature`, `max_tokens`, `top_p`, `timeout_seconds`). - Output format: `text`, `markdown`, or `json`. - Validation mode: `none`, `basic`, `json`, `json_schema`. - Repair attempts: bounded retries for structured modes (`json`, `json_schema`) when output validation fails. - Run metadata: IDs/hashes/model/timing/usage/validation details for auditability. ## Build and Test Build: ```bash go build -o scriptorium ./cmd/scriptorium ``` Run tests: ```bash go test ./... ``` Run CLI locally: ```bash go run ./cmd/scriptorium run --help ``` ## CLI Usage ### `scriptorium run` Required flags: - `--profile-dir` - `--profile-id` - `--input` (repeatable `name=path`) Optional flags: - `--var` (repeatable `name=value`) - `--out` - `--llm-base-url` - `--llm-api-key` - `--model` - `--temperature` - `--max-tokens` - `--schema-dir` - `--timeout` If `--llm-base-url` and/or `--model` are omitted, profile `model_defaults` must provide them. Markdown summary example: ```bash go run ./cmd/scriptorium run \ --profile-dir ./profiles \ --profile-id generic.markdown_summary \ --input transcript=./examples/fixtures/transcript.md \ --input glossary=./examples/fixtures/glossary.yml \ --out ./out.md ``` Same run with explicit local OpenAI-compatible endpoint (for example vLLM): ```bash go run ./cmd/scriptorium run \ --profile-dir ./profiles \ --profile-id generic.markdown_summary \ --input transcript=./examples/fixtures/transcript.md \ --input glossary=./examples/fixtures/glossary.yml \ --llm-base-url http://localhost:8000/v1 \ --model gpt-4o-mini \ --out ./out.md ``` Passing template variables: ```bash go run ./cmd/scriptorium run \ --profile-dir ./profiles \ --profile-id generic.markdown_summary \ --input transcript=./examples/fixtures/transcript.md \ --input glossary=./examples/fixtures/glossary.yml \ --var session_date=2026-05-04 \ --var facilitator="Eris" \ --out ./out.md ``` Output behavior: - Artifact content goes to stdout unless `--out` is set. - Summaries and errors are written to stderr. - Exit code `2` indicates run succeeded but validation status is `failed`. ### `scriptorium serve` Starts HTTP API. Required flags: - `--profile-dir` - `--llm-base-url` Common optional flags: - `--addr` (default `:8080`) - `--schema-dir` (default `.`) - `--llm-api-key` - `--model` - `--timeout` (default `10m`) ## HTTP API Run endpoint: - `POST /v1/runs` Request example: ```json { "profile_id": "generic.structured_events", "profile_version": "1.0.0", "inputs": { "transcript": {"type": "file", "uri": "./examples/fixtures/transcript.md"}, "glossary": {"type": "file", "uri": "./examples/fixtures/glossary.yml"} }, "vars": { "session_date": "2026-05-04" }, "model": { "endpoint": "http://localhost:8000/v1", "model": "gpt-4o-mini", "temperature": 0.0, "max_tokens": 600, "top_p": 1.0, "timeout_seconds": 120 } } ``` Response shape: ```json { "artifact": { "name": "output", "content_type": "application/json", "body": "{...}", "uri": "", "size": 123, "hash": "..." }, "validation": { "status": "passed", "mode": "json_schema", "errors": [], "schema_path": "structured_events.schema.json", "repair_attempts": 0, "is_valid": true }, "metadata": { "run_id": "xxxxxxxx-xxxx-4xxx-8xxx-xxxxxxxxxxxx", "profile_id": "generic.structured_events", "profile_version": "1.0.0", "profile_hash": "...", "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": 600, "top_p": 1, "timeout_seconds": 120 }, "input_hashes": {"transcript": "...", "glossary": "..."}, "prompt_hash": "...", "usage": {"prompt_tokens": 10, "completion_tokens": 20, "total_tokens": 30}, "start_time": "...", "end_time": "...", "duration_ms": 1523, "validation_mode": "json_schema", "validation_status": "passed", "repair_attempts_used": 0 }, "raw_model_output": "{...}" } ``` Validation content failures are returned as successful run responses (`200`) with `validation.status = "failed"`; raw model output is preserved in `raw_model_output`. Error response shape: ```json { "error": { "code": "artifact_read_failed", "message": "failed to read input artifact" } } ``` ## Prompt Profile Authoring ### Minimal Markdown profile ```yaml id: generic.markdown_summary version: "1.0.0" expected_inputs: - transcript templates: - role: system content: "You are a concise assistant." - role: user content: | Summarize: {{input "transcript"}} model_defaults: endpoint: http://localhost:8000/v1 model: gpt-4o-mini temperature: 0.2 max_tokens: 700 output_format: markdown validation: validation_mode: basic ``` ### Structured JSON profile with schema validation ```yaml id: generic.structured_events version: "1.0.0" expected_inputs: - transcript templates: - role: system content: "Return only JSON." - role: user content: | Extract events from: {{input "transcript"}} model_defaults: endpoint: http://localhost:8000/v1 model: gpt-4o-mini output_format: json validation: format: json validation_mode: json_schema schema_path: structured_events.schema.json repair_attempts: 1 ``` `repair_attempts` is bounded. Repair is attempted only for structured validation modes. ## Validation Modes Supported modes: - `none`: skipped validation result. - `basic`: fails if output is empty/whitespace. - `json`: output must parse as JSON. - `json_schema`: output must parse as JSON and satisfy the configured schema. Validation failures caused by output content are represented in `validation` and do not discard raw model output. ## Repository Examples - Profiles: `profiles/` - Schemas: `schemas/` - Fixtures: `examples/fixtures/` - Local experimentation: `local-test/` ## Development Notes - Core is generic and follows a ports-and-adapters style. - Domain/usecase packages do not depend on HTTP/CLI/wire types. - To add a new LLM adapter: implement `internal/llm.Client`. - To add a new artifact reader: implement/extend `internal/artifact.Reader` routing. - To add a new validation mode: extend `internal/validate` and keep run semantics stable.