Files
scriptorium/README.md

7.3 KiB

scriptorium

Scriptorium is a generic prompt-definition execution engine written in Go.

Given named input artifacts and a prompt definition, Scriptorium:

  1. Loads the prompt definition.
  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 definition: YAML config for templates, inputs, output format, and validation behavior.
  • Execution profile: conceptual runtime config (endpoint/model/timeouts/auth source). In this transition, execution settings are supplied as run-time overrides.
  • Named inputs: logical names (for example transcript, glossary) mapped to artifact references.
  • Artifact refs: currently file and inline are supported.
  • Template variables: key/value vars passed at run time and referenced as {{.var_name}}.
  • Execution target: endpoint/model plus generation/runtime parameters (temperature, max_tokens, top_p, timeout_seconds, reasoning_effort, api_key_env).
  • 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.

Build and Test

go build -o scriptorium ./cmd/scriptorium
go test ./...

CLI Usage

scriptorium run

Required flags:

  • --prompt-dir
  • --profile-dir
  • --prompt
  • --input (repeatable name=path)

Common optional flags:

  • --profile (execution profile selector; falls back to prompt default_profile)
  • --var (repeatable name=value)
  • --out
  • --llm-base-url
  • --model
  • --api-key-env
  • --temperature
  • --max-tokens
  • --schema-dir
  • --timeout

Current transitional behavior: execution-profile loading is not implemented yet, so run-time execution settings must be supplied via overrides. In practice, provide at least endpoint and model (--llm-base-url and --model).

Example:

export SCRIPTORIUM_API_KEY="your-key"

go run ./cmd/scriptorium run \
  --prompt-dir ./prompts \
  --profile-dir ./profiles \
  --prompt generic.markdown_summary \
  --profile local-fast \
  --input transcript=./examples/fixtures/transcript.md \
  --input glossary=./examples/fixtures/glossary.yml \
  --llm-base-url http://localhost:8000/v1 \
  --model gpt-4o-mini \
  --api-key-env SCRIPTORIUM_API_KEY \
  --out ./out.md

Output behavior:

  • Artifact content goes to stdout unless --out is set.
  • Summaries and errors are written to stderr.
  • Exit code 2 means the run succeeded but validation status is failed.

scriptorium serve

Starts HTTP API.

Required flags:

  • --prompt-dir
  • --profile-dir

Common optional flags:

  • --addr (default :8080)
  • --schema-dir (default .)
  • --model
  • --timeout (default 10m)

HTTP API

Endpoint:

  • POST /v1/runs

No built-in authentication is provided by the server itself. Deploy behind a trusted boundary or gateway.

Request example:

{
  "prompt_id": "generic.structured_events",
  "prompt_version": "1.0.0",
  "profile_id": "local-default",
  "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,
    "api_key_env": "SCRIPTORIUM_API_KEY"
  }
}

Response shape:

{
  "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",
    "prompt_id": "generic.structured_events",
    "prompt_version": "1.0.0",
    "prompt_hash": "...",
    "rendered_prompt_hash": "...",
    "selected_profile_id": "local-default",
    "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,
      "api_key_env": "SCRIPTORIUM_API_KEY"
    },
    "input_hashes": {"transcript": "...", "glossary": "..."},
    "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 return 200 with validation.status = "failed" and preserve raw_model_output.

Error response shape:

{
  "error": {
    "code": "artifact_read_failed",
    "message": "failed to read input artifact"
  }
}

Prompt Definition Authoring

Minimal Markdown prompt definition

id: generic.markdown_summary
version: "1.0.0"
default_profile: local-default
inputs:
  - name: transcript
    required: true
templates:
  - role: system
    content: "You are a concise assistant."
  - role: user
    content: |
      Summarize:
      {{input "transcript"}}
output_format: markdown
validation:
  validation_mode: basic

Structured JSON prompt definition with schema validation

id: generic.structured_events
version: "1.0.0"
default_profile: local-default
inputs:
  - name: transcript
    required: true
templates:
  - role: system
    content: "Return only JSON."
  - role: user
    content: |
      Extract events from:
      {{input "transcript"}}
output_format: json
validation:
  format: json
  validation_mode: json_schema
  schema_path: structured_events.schema.json
  repair_attempts: 1

repair_attempts is strictly bounded and only applies to structured validation modes.

Validation Modes

  • none: skipped validation result.
  • basic: fails for empty/whitespace output.
  • json: output must parse as JSON.
  • json_schema: output must parse as JSON and satisfy configured schema.

Validation content failures are returned in the structured result; raw model output is preserved.

Examples

  • Prompt definitions: prompts/
  • Execution profiles: profiles/
  • Schemas: schemas/
  • Fixtures: examples/fixtures/
  • Local experimentation: local-test/

Development Notes

  • Core follows ports-and-adapters and remains domain-generic.
  • Domain/usecase packages do not depend on HTTP/CLI wire DTOs.
  • To add a new LLM adapter: implement internal/llm.Client.
  • To add a new artifact reader: extend internal/artifact.Reader routing.
  • To add a new validation mode: extend internal/validate and preserve run semantics.