# 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` ## 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`.