# Adapter Internals ## Purpose Scriptorium adapters translate executable inputs into Promptkit public requests and translate Promptkit results or errors back to CLI or HTTP behavior. They own IO and presentation mechanics, not framework decisions. External contracts are canonical in the [CLI reference](../cli.md) and [HTTP API reference](../api.md). Promptkit's public engine contract is described by its tagged [Go consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.1/docs/consumers/pkg-promptkit.md). ## Components And Collaborators - `cmd/scriptorium` passes process arguments and streams to `internal/adapter/cli`. - `internal/adapter/cli` resolves settings through `internal/config`, constructs `promptkit.Engine`, maps CLI values to `promptkit.RunRequest`, and owns output files, summaries, and exit codes. - `internal/config` delegates application YAML decoding, default resolution, overrides, and validation ordering to ConfigKit. The CLI supplies only explicitly visited application flags as overrides and renders safe structured load diagnostics on stderr. - `internal/adapter/http` strictly decodes request DTOs, maps them to Promptkit public values, calls its adapter-owned `Runner` interface, and maps results and errors to HTTP DTOs. - `internal/format` renders `promptkit.PreparedRun` values as deterministic text or JSON. - `internal/report` maps Promptkit's terminal execution event to a small application-owned value without invoking the engine or writing output. ## Wiring Flows ### CLI `run` calls `promptkit.Engine.Run`; `render` calls `promptkit.Engine.Prepare`. Both share request mapping for prompt ID/version and profile selection, optional file inputs, variables, and presence-aware execution overrides. Omitted framework settings remain zero values so Promptkit resolves its own defaults and definition-required inputs. The application retry setting enters shared engine construction, while a run/render flag enters only the mapped request. The server uses the same engine setting and retains one backend admission state. Render prepares without generation. `inspect prompt` maps the selected ID and optional version to `promptkit.Engine.InspectPrompt`, then formats Scriptorium-owned inspection data. It constructs the same configuration-aware engine but does not perform preparation or generation. `inspect profile` maps an explicit profile ID to `Engine.InspectProfile` and formats a safe application-owned effective profile view. It intentionally does not require prompt, schema, or artifact sources. The `config` family loads the same application ConfigKit result once and uses its validation, effective-output, source, and explanation views directly. It does not construct a Promptkit engine. The CLI maps source records into a small JSON DTO for `sources`; `show` and `explain` use ConfigKit's own writers. `serve` constructs Scriptorium's restricted HTTP artifact reader, injects it with `promptkit.WithArtifactReader`, passes the engine through the HTTP adapter's consumer-owned `Runner` interface, and starts the server. The command paths assemble the engine from the same resolved prompt, profile, and schema directories plus configured custom backends. Each backend is mapped to Promptkit's public `Backend` value and registered during engine construction, so one constructed server engine retains one immutable backend registry and its associated capacity state. ### HTTP The handler enforces transport limits and strict JSON decoding before mapping DTOs into `promptkit.RunRequest`, `promptkit.ArtifactRef`, and `promptkit.ExecutionTargetOverride`. On success it reads Promptkit artifact, validation, model, usage, and metadata values directly. The optional HTTP retry count maps to `RunRequest.TransientRetries` without mutating the shared engine. Negative values are rejected before invocation; Promptkit controls retries and backend admission for concurrent requests. Failure mapping uses `errors.Is` against Promptkit's public sentinels and the HTTP reader's Scriptorium-owned containment and size errors. Wrapped reader errors preserve their identity through Promptkit's artifact-load boundary. The report collector is per invocation. It ignores nonterminal events and copies terminal aggregates once, including usage presence and completeness. It retains no history or shared state; adapters decide whether to attach it and how to present its snapshot. CLI `run` attaches one only when a report path is selected, writes generated output first on success, and then writes the terminal snapshot when present. Its report path remains untouched for pre-invocation failures or absent terminal observations; report and artifact writes are independent. HTTP `POST /v1/runs` attaches a separate collector to each invocation only when `include_execution_report` is true. Its optional top-level `execution` field appears in success or error envelopes only when Promptkit emits a terminal event. Pre-invocation adapter errors and absent terminal events leave it out. The complete serialized success or report-bearing error response is subject to the configured response-size limit; overflow returns the compact 413 error without a report. Field meanings are owned by the [API contract](../api.md#execution-report). ## Package-Local Guarantees - Adapters contain no copied framework types or orchestration. - Configuration is resolved before Promptkit engine construction. - Explicit numeric overrides preserve presence, including zero. - HTTP DTO and error mapping remains stable and transport-owned. - Resolved secrets are not serialized or printed. - No adapter creates durable run state. ## Verification Inspect: - `internal/adapter/cli/run_test.go` - `internal/adapter/http/handler_test.go` - `internal/adapter/http/artifact_reader_test.go` - `internal/format/prepared_run_test.go` - `internal/adapter/dependency_test.go` The adapter tests protect parsing, configuration mapping, output, status mapping, restricted artifacts, and representative real Promptkit-engine workflows. The dependency test protects the repository boundary. ## Change Recipes For a CLI or HTTP change: 1. identify the Scriptorium-owned external contract; 2. map through Promptkit public values without copying framework semantics; 3. add or update the narrow application-owned test; 4. update the canonical Scriptorium contract; and 5. coordinate and tag Promptkit first if a required public capability is genuinely absent. Update [source internals](sources.md) when application source locations or HTTP artifact containment changes.