# Architecture This document is the development architecture policy for Scriptorium. It is for developers and LLM coding agents. User-facing behavior belongs in `README.md` and the docs under `docs/` that target operators/users. ## Project Shape Scriptorium is a narrow prompt-execution application with three entry paths: - CLI `run` - CLI `render` - HTTP `POST /v1/runs` through `serve` - public Go package `gitea.maximumdirect.net/eric/scriptorium` Domain behavior is centralized in `internal/usecase` and `internal/domain`. ## Core Principles - Keep orchestration narrow: Scriptorium executes one prompt request; it is not a multi-step workflow engine. - Keep adapter logic thin: adapters map external shapes to domain requests/results and should not hold domain decisions. - Keep boundaries explicit: repositories/loaders/renderers/validators/LLM client stay behind package interfaces. - Keep config strict: YAML/JSON decoding for external inputs should reject unknown fields. - Keep secrets out of payloads: raw API key values must not be accepted or emitted. ## Package Boundaries Current package map: - root package `scriptorium`: public Go facade over engine construction, source options, request/result types, and error mapping. - `cmd/scriptorium`: process entrypoint. - `internal/adapter/cli`: command parsing, app wiring for CLI commands, output behavior. - `internal/adapter/http`: HTTP DTO mapping and error/status mapping. - `internal/config`: application settings loading and CLI override precedence. - `internal/defaults`: compile-time default constants. - `internal/domain`: core request/result and contract types. - `internal/usecase`: `Runner` prepare/run orchestration and repair-hook boundary. - `internal/promptdef`: filesystem prompt-definition repository. - `internal/profile`: filesystem, `fs.FS`, and overlay execution-profile repositories. - `internal/profile/builtin`: embedded built-in execution profiles. - `internal/filecatalog`: shared YAML discovery and `fs.FS` source helpers. - `internal/artifact`: artifact reference readers. - `internal/prompt`: template renderer. - `internal/llm`: provider-neutral LLM client interface and OpenAI-compatible implementation. - `internal/validate`: validator interfaces and standard implementation. - `internal/format`: prepared-run output formatting. Detailed component behavior is documented in: - `docs/internal/runner.md` - `docs/internal/adapters.md` - `docs/internal/sources.md` ## Configuration And Precedence Application settings are resolved as: 1. built-in defaults 2. config file values 3. CLI overrides `config.yml` is for application wiring (directories, server address, render default format), not prompt/profile runtime execution settings. Profile selection and runtime model resolution remain use-case concerns. ## State And Persistence Policy Scriptorium has no durable run-state store. - No built-in resume/checkpoint/archive behavior. - Recovery model is rerun after correcting inputs/config/environment. ## External Integration Policy Current external contracts: - inbound HTTP contract: `POST /v1/runs`, documented canonically in `docs/api.md` - outbound model contract: OpenAI-compatible chat completions subset - subprocess contract for integrators: CLI `run`/`render` - public Go package contract: `docs/consumers/pkg-scriptorium.md` Integration docs belong under `docs/integrations/`. ## Error Handling And Logging - Wrap errors with domain/operation context. - Map domain errors to adapter-appropriate statuses/codes without leaking sensitive internals. - Keep stderr summaries concise for CLI success/error paths. - Never emit raw secret values. ## Testing Expectations - Core runner behavior should be covered with isolated unit tests and fixture-based integration tests. - Adapter behavior should be tested for parse/mapping/error semantics. - Config parsing, prompt/profile loading, validator behavior, and LLM client error handling should remain covered by package tests. - Repository-level docs/examples that claim runnable behavior should be validated by tests or smoke commands. ## Documentation Expectations - Document implemented behavior only outside `docs/roadmap/`. - Keep canonical reference locations stable (`docs/cli.md`, `docs/config.md`, `docs/operations.md`, `docs/troubleshooting.md`, `docs/internal/`). - Update docs in the same change when architecture-relevant behavior changes. ## Architectural Invariants - `Runner.Run` reuses `Runner.Prepare` flow. - CLI and HTTP currently instantiate `Runner` without a repairer. - Artifact reading supports `inline` and `file` references. - Unknown input fields in config/prompt/profile/http JSON should be rejected by strict decoding. - Raw API key values must not be accepted through config/HTTP payloads. ## Non-Goals - Do not move orchestration responsibilities from external callers into Scriptorium. - Do not add adapter-specific business logic in `internal/adapter/*` packages. - Do not bypass repository/renderer/validator/LLM boundaries by introducing cross-package coupling. Work that is not implemented belongs in `docs/roadmap/`.