# Adapter Internals ## Purpose Adapters translate external interfaces into domain requests and translate domain results back out. They wire dependencies, apply app config, and own IO concerns, but they do not make runner decisions. Source-loading behavior belongs in `docs/internal/sources.md`. User-facing CLI, HTTP, and package contracts belong in `docs/cli.md`, `docs/api.md`, and `docs/consumers/pkg-scriptorium.md`. ## Adapter Map - `cmd/scriptorium`: process entrypoint. - `internal/adapter/cli`: command parsing, config handoff, runner construction, stdout/stderr, exit codes. - `internal/adapter/http`: `POST /v1/runs` request/response mapping and HTTP error/status mapping. - root package `scriptorium`: public Go facade over internal runner types and dependencies. Supporting implementation packages used during adapter wiring: - `internal/config` - `internal/defaults` - `internal/format` - `internal/llm` - `internal/prompt` ## Inputs And Outputs CLI adapter: - Input: process args, optional config file, filesystem sources, environment variables. - Output: process exit code, stdout artifact/prepared output, stderr summaries and errors. HTTP adapter: - Input: HTTP request method/path/headers/body for `POST /v1/runs`. - Output: JSON success or error body with mapped status code. Public Go facade: - Input: typed `scriptorium.Config`, `Option`, and `RunRequest` values. - Output: typed `PreparedRun` and `RunResult` values plus public sentinel errors. ## Boundaries - Adapters convert external shapes to `domain.RunRequest` and back. - Runner orchestration remains in `internal/usecase`. - Prompt/profile/schema/artifact source rules remain in repository, validator, and artifact packages. - LLM provider request serialization remains in `internal/llm`. - Public package types are facade types; internal domain types do not leak across the package boundary. ## Config Fields Used Adapter app settings: - `prompt_dir` - `profile_dir` - `schema_dir` - `server.addr` - `server.artifact_root` - `server.max_request_bytes` - `server.max_artifact_bytes` - `server.max_response_bytes` - `defaults.render_format` Execution request/profile settings passed through the runner: - `endpoint` - `model` - `temperature` - `max_tokens` - `top_p` - `timeout_seconds` - `service_tier` - `api_key_env` - `reasoning_effort` - `extra_params` CLI and HTTP preserve numeric override presence so omitted values and explicit zero values remain distinct. ## CLI Adapter Implemented commands: - `run` - `render` - `serve` Behavior: - `run` constructs a runner with direct filesystem artifact reading and calls `Runner.Run`. - `render` constructs a runner and calls `Runner.Prepare`; it does not call the LLM. - `serve` constructs a restricted artifact reader and HTTP handler, then starts an unauthenticated HTTP server. - `run` exits `2` when generation succeeds but validation fails. - parse, runtime, and output-write errors exit `1`. - deprecated `--prompt-id` and `--profile-id` aliases are accepted. ## HTTP Adapter Behavior: - Accepts only `POST /v1/runs`. - Decodes JSON strictly and rejects unknown fields and trailing JSON tokens. - Rejects empty `prompt_id` and empty `inputs` before calling the runner. - Does not accept raw API key values in the request body. - Returns validation failures as `200` responses with failed validation details. - Maps request-body, artifact, and encoded-response size failures to `413`. - Maps domain and repository errors to stable error codes without returning wrapped internal cause text. The HTTP adapter has no built-in authentication or authorization. Deployment controls must be provided outside the process. ## Public Go Facade Behavior: - `NewEngine` wires the same default runner components as CLI/HTTP unless options override them. - Prompt, profile, and schema sources may come from directories, single files, or `fs.FS` roots. - `WithProfiles` adds in-memory profiles ahead of file-backed and built-in profiles. - `WithLLMClient` injects custom model behavior. - `RunRequest.APIKey` is request-scoped and direct; it is used only for generation and is stripped from public results. - internal errors are mapped to public sentinels in `errors.go`. ## Failure Behavior Adapters should: - keep external error payloads concise and stable. - avoid leaking raw secret values. - use sentinels and typed errors for mapping. - preserve strict external input decoding. - keep validation content failures distinct from runtime errors. CLI writes human-readable summaries to stderr. HTTP writes JSON error envelopes. The public Go facade returns typed errors. ## State And Manifests Adapters do not add durable run state. - No adapter writes run manifests. - No adapter implements checkpoint, skip, or resume behavior. - CLI output files are caller-selected artifacts, not internal state. ## Tests To Inspect - `internal/adapter/cli/run_test.go` - `internal/adapter/http/handler_test.go` - `engine_test.go` - `internal/format/prepared_run_test.go` - `internal/llm/openai_compatible_client_test.go` ## Change Recipes ### Application Configuration Fields 1. Add the field to the relevant `internal/config` shape and default handling. 2. Parse and validate it, then preserve configuration and CLI-override precedence while wiring it through its consuming adapter. 3. Add focused configuration and adapter tests for parsing, mapping, and effective behavior. 4. Update the [configuration contract](../config.md) and any external contract affected by the new behavior. ### CLI Flags 1. Add the flag to the relevant command in `internal/adapter/cli/run.go`. 2. Keep command scope and application-configuration precedence intentional. 3. Add or update parser and command tests in `internal/adapter/cli/run_test.go`. 4. Update the [CLI contract](../cli.md) and any maintained examples affected by the invocation. ### Adapter Capabilities 1. Define or reuse the appropriate domain or use-case interface boundary. 2. Implement translation and IO behavior in the adapter without moving use-case decisions out of `internal/usecase`. 3. Add focused mapping, parsing, and error-behavior tests. 4. Update this document and the affected canonical public or integration contract. Update [source internals](sources.md) when source-loading behavior changes. ## Architectural Invariants - Adapter packages stay thin and translation-focused. - App config is resolved before dependency construction. - External input strictness is part of contract stability. - CLI and HTTP construct runners without a repairer. - HTTP endpoint details remain canonical in `docs/api.md`. - Public Go package details remain canonical in `docs/consumers/pkg-scriptorium.md`.