# Architecture Policy **Base Policy Version:** 1.3 **Last Updated**: 2026-09-28 **Upstream Source:** https://gitea.maximumdirect.net/eric/policy/src/commit/d84a38ebab26f048cafbe59a2246700c35d29843/docs/policy/architecture.md ## Purpose And Ownership The adopted policy defines the application's purpose and the architectural constraints contributors must follow. It owns system boundaries, responsibility and dependency rules, established invariants, and explicit non-goals. Describe the concrete package inventory and implementation mechanics in internal documentation. Link to canonical public contracts for their exact behavior and to ADRs for decision rationale. ## Architectural Approach Hexagonal architecture is strongly recommended, including encapsulating external integrations and APIs within internal adapters. Keep domain and application logic independent of external integration details, and make dependency direction clear in the adopted policy. Implement that separation with proportionate, idiomatic code. Choose interfaces and package layout to serve the application's actual boundaries. Use adapters for collaborators with external integration responsibilities. ## Adopted Constraints And Implemented Structure Architectural constraints govern current and future development. Record implemented structure accurately, proposals and implementation status in the roadmap, and significant decisions and rationale in ADRs. Describe a target structure as implemented when its changes land. Constraints must reflect deliberately selected requirements and decisions. Do not promote incidental implementation choices into architectural invariants. ## Scriptorium's Purpose And System Shape Scriptorium is an executable application with CLI `run`, `render`, `inspect`, and `config` command families and an HTTP service started by `serve`. It offers simple, request-independent execution of predefined prompts, not a reusable Scriptorium root Go API or a workflow framework. The [internal overview](../internal/overview.md) owns the concrete package inventory; [adapter internals](../internal/adapters.md) and [source internals](../internal/sources.md) own implementation mechanics. ## Framework And Application Boundaries Scriptorium consumes [Promptkit v0.11.1](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.1/docs/consumers/pkg-promptkit.md) through its supported public root package. Promptkit owns prompt execution, preparation, prompt and profile formats, built-in profiles, model-client behavior, validation, and framework defaults. Scriptorium owns application configuration, executable CLI and HTTP adapters, prepared-run and definition-inspection presentation, process behavior, and HTTP deployment policy. The [format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.1/docs/formats.md) and [outbound integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.1/docs/integrations/openai-compatible-chat.md) remain Promptkit's contracts. Scriptorium uses ConfigKit v0.4.1 for strict application YAML decoding, resolution, and validation flow. Scriptorium retains its application schema, defaults, normalization, validation rules, source selection, and CLI override mapping. ConfigKit does not own Promptkit framework sources or HTTP artifact containment. The [configuration contract](../config.md) owns externally observable configuration behavior. Application code may import Promptkit's public root package, but not its `internal` packages or catalog modules. It must not recreate the removed Scriptorium framework facade or former framework package families. Use consumer-owned interfaces only where substitution at an adapter boundary is needed. Omitted framework settings pass as zero values so Promptkit applies its own defaults. Cross-project changes land and release in Promptkit before Scriptorium adopts its tagged dependency; do not commit Go workspaces, local replacements, vendored Promptkit source, or unpublished dependency assumptions. The repository's architecture guard protects these import and removal boundaries. Adapter separation does not require an interface for every type, extra wrappers, or a fixed directory tree. ## Definition Support And Request State As decided in [ADR 0004](../adr/0004-definition-boundary.md), Scriptorium aims to support the complete set of features in valid Promptkit prompt and profile definitions for its selected upstream version. Promptkit remains the canonical parser and validator. Library-only features are considered individually against Scriptorium's simple predefined-prompt execution model. External YAML and JSON decoding remains strict. Adapters map external values through Promptkit public requests and results without taking over framework orchestration. Explicit numeric request overrides preserve presence, including zero. Adapters map Promptkit public error identities to CLI exits or HTTP statuses without classifying by message text. Raw API keys are not accepted in Scriptorium configuration, CLI arguments, or HTTP payloads, and resolved secrets must not be emitted. Each execution request is self-contained from the caller's perspective; no conversation or workflow state is retained from completed requests. This does not preclude process-scoped operational state. A server shares its Promptkit engine, backend registry, capacity admission and queue accounting across relevant concurrent requests so configured backend limits cannot be bypassed by per-request construction. In-flight coordination, cancellation, and server lifecycle state must be concurrency-safe. None of this creates a durable workflow, checkpoint, cache, or resume contract; recovery is a new request after correcting inputs, configuration, or environment. ## Non-Goals - Do not recreate an in-process Scriptorium framework API or compatibility facade. - Do not copy Promptkit types, defaults, built-in profiles, or implementation into Scriptorium. - Do not move CLI, inbound HTTP, process, or deployment policy into Promptkit. - Do not add durable workflow, archive, or resume behavior. - Do not add application-managed prompt modification, follow-up message flows, conversation management, or multi-step workflow orchestration. ## Trust Boundaries And Threat Scope Ordinary CLI file loading belongs to Promptkit. For untrusted inbound HTTP artifact references, Scriptorium injects a restricted `promptkit.ArtifactReader`. It denies file references without an artifact root, applies the configured byte limit, and enforces lexical root containment. The operating system follows symlinks after that lexical check. This is not a filesystem sandbox or a defense against a privileged actor concurrently modifying the host filesystem; that threat is outside the adopted scope. Do not infer stronger defenses from hypothetical threats. Raise unsettled scope decisions under the [agent policy](agents.md). The [HTTP API](../api.md) owns observable request outcomes, the [configuration contract](../config.md) owns credential supply, and [operations](../operations.md) owns deployment permissions and root selection. The [source internals](../internal/sources.md) describe reader mechanics.