Files
scriptorium/architecture.md

7.6 KiB

Scriptorium Architecture

1. Purpose and Non-Goals

Scriptorium is a prompt-definition execution engine.

It accepts named input artifacts, renders prompt templates, calls an LLM, validates output, optionally performs bounded structured-output repair, and returns an artifact with metadata.

Scriptorium is not an orchestrator. It must not own transcription, transcript merge/polish steps, notifications, or cross-step workflow control.

For the motivating D&D workflow:

  • Narratio orchestrates.
  • WhisperX transcribes.
  • Seriatim merges transcripts.
  • Audita polishes transcripts.
  • Scriptorium generates final artifacts from prepared inputs.

Core Go code remains generic.

2. Current Architecture

Current implementation structure:

  • cmd/scriptorium: binary entrypoint.
  • internal/domain: core domain contracts.
  • internal/usecase: Runner run flow, validation integration, bounded repair coordination.
  • internal/profile: transitional filesystem prompt-definition repository (package rename deferred).
  • internal/artifact: input artifact resolution (inline, file).
  • internal/prompt: template rendering.
  • internal/llm: provider-neutral client interface + OpenAI-compatible HTTP adapter.
  • internal/validate: validation implementation (none/basic/json/json_schema).
  • internal/adapter/cli: CLI adapter.
  • internal/adapter/http: HTTP adapter (POST /v1/runs).

3. Run Data Flow

Runner.Run(ctx, RunRequest) currently executes:

  1. Validate request (prompt_id required).
  2. Load PromptDefinition by ID/version.
  3. Determine selected profile ID (request.profile_id or prompt default_profile).
  4. Resolve effective execution target from request override (execution-profile loading is deferred in this phase).
  5. Resolve named input artifact refs.
  6. Render prompt messages.
  7. Hash prompt definition and rendered prompt.
  8. Call LLM client with GenerateRequest.
  9. Build output artifact.
  10. Validate output.
  11. If structured validation failed and repair is enabled, run bounded repair attempts and re-validate.
  12. Return RunResult with artifact, raw output, validation result, metadata.

Validation content failures are returned as successful runs with validation.status=failed.

4. Package Responsibilities

  • domain

    • Owns core nouns/contracts.
    • Must not depend on adapters/provider SDK types.
  • usecase

    • Owns single-run orchestration across ports.
    • Owns bounded repair control flow.
    • Must not own transport/wire concerns.
  • profile (transitional)

    • Currently loads prompt definitions from YAML.
    • Package naming split (prompt definition repo vs execution profile repo) is deferred follow-up.
  • artifact

    • Loads artifacts from refs and normalizes payload metadata.
  • prompt

    • Renders templates and enforces required inputs.
  • llm

    • Defines generation client contract and protocol adapters.
  • validate

    • Owns output validation semantics and schema validation.
  • adapter/http, adapter/cli

    • Own request/response/flag mapping only.
    • Delegate business flow to usecase.Runner.

5. Domain Model (Current)

Key types:

  • PromptDefinition
    • id, version, default_profile, inputs, templates, output_format, validation.
  • ExecutionProfile
    • Execution/runtime settings shape (endpoint, model, timeouts, api_key_env, etc.).
    • Loading/persistence is deferred in this pass.
  • ExecutionTarget
    • Effective execution settings for a run.
  • RunRequest
    • prompt_id, prompt_version, optional profile_id, inputs, vars, optional execution override, optional validation override.
  • RunResult
    • Output artifact, validation, raw output, prompt/profile/model metadata, hashes, timing, usage.
  • ArtifactRef / Artifact
    • Input reference and loaded content contracts.
  • RenderedPrompt / RenderedMessage
    • Provider-neutral rendered prompt.
  • GenerateRequest / GenerateResponse
    • Provider-neutral model I/O.

6. Interfaces and Adapters

Primary ports:

  • profile.Repository (transitional prompt-definition lookup)
  • artifact.Reader
  • prompt.Renderer
  • llm.Client
  • validate.Validator
  • usecase.OutputRepairer (usecase-local)

Current adapters:

  • Prompt definition repository: filesystem YAML loader.
  • Artifact readers: file, inline via composite reader.
  • Prompt renderer: Go templates with input helper.
  • LLM adapter: OpenAI-compatible /chat/completions over net/http.
  • Validator: standard validator (none/basic/json/json_schema).
  • CLI/HTTP adapters.

7. Validation and Repair Model

Validation modes:

  • none
  • basic
  • json
  • json_schema

Repair behavior:

  • Applies only to structured modes (json, json_schema).
  • Triggered only on failed validation and only when repair_attempts > 0.
  • Strictly bounded by repair_attempts.
  • Uses a narrow repair prompt asking for corrected JSON only.
  • Runtime validator/repair errors are run errors.

8. Public Contracts

CLI

Commands:

  • scriptorium run
  • scriptorium serve

run flags:

  • Required: --profile-dir, --prompt-id, --input.
  • Optional: --profile-id, --var, --out, --llm-base-url, --model, --api-key-env, --temperature, --max-tokens, --schema-dir, --timeout.

Current transitional runtime behavior:

  • Prompt definitions may provide default_profile selection.
  • Execution-profile loading is deferred; execution settings must currently be supplied via run-time overrides.

HTTP

  • Endpoint: POST /v1/runs.
  • Request maps to RunRequest with prompt_id (required), inputs, optional profile_id, vars, optional execution override (model object).
  • Response includes artifact, validation, metadata, raw_model_output.
  • Validation content failures return 200 with failed validation status.
  • Error response shape: { "error": { "code": "...", "message": "..." } }.

Prompt Definition YAML

Current prompt-definition fields:

  • id, version, optional default_profile, optional description
  • inputs[] with name, required, optional content_type, optional description
  • templates[] with role and either content or content_file
  • output_format
  • validation (format, validation_mode, schema_path, repair_attempts)

Strict YAML decoding (KnownFields) is enabled.

API Key Policy

  • Raw API keys are not accepted in YAML, CLI flags, HTTP body, or domain metadata.
  • Auth is configured only by env var reference (api_key_env), resolved at request time by the LLM adapter.

9. Extension Points (Future Work)

Planned next extensions should reuse current boundaries:

  • Execution-profile repository/loader implementation.
  • Split transitional internal/profile into clearer prompt-definition/profile repositories.
  • S3 artifact refs.
  • Token budgeting/policy layer.
  • Streaming generation.
  • Batch run use case.
  • Additional provider adapters.
  • Additional validation modes.

10. Architectural Guardrails

  • No D&D-specific logic in core Go packages.
  • No orchestration creep into Scriptorium.
  • No unbounded repair loops.
  • No silent content truncation/omission.
  • Do not log full prompts/artifacts by default.
  • Keep provider-specific wire/SDK details out of domain types.
  • Keep adapters thin.

11. Testing Strategy

Protect these behaviors with focused tests:

  • Prompt-definition loading/validation errors.
  • Artifact loading/hash/content-type behavior.
  • Prompt rendering required-input and template error paths.
  • LLM adapter request/response/auth/error/timeout behavior.
  • Runner success/failure/metadata behavior.
  • Validation failure raw-output preservation.
  • Bounded repair behavior.
  • HTTP mapping and error mapping.
  • CLI parsing and output stream separation.

Prefer small unit tests and minimal integration-style tests with fake LLMs.