diff --git a/README.md b/README.md index 7003b54..aa21003 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,15 @@ -# scriptorium +# Scriptorium -Scriptorium is a narrow prompt-execution application for rendering prompt -requests, running them against OpenAI-compatible chat-completions endpoints, and -serving the same run workflow over HTTP. +Scriptorium is a prompt-execution application with a command-line interface and +an HTTP service. It prepares prompt requests, runs them against +OpenAI-compatible model endpoints, and returns generated output with validation +metadata. -It keeps prompt definitions, execution profiles, schemas, and input artifacts as -separate files so prompts can be reviewed and reused without baking model -runtime settings into application code. +The application uses +[Promptkit v0.1.0](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/) +for prompt, profile, schema, preparation, generation, and validation behavior. +Scriptorium owns executable configuration, CLI and HTTP mapping, process +behavior, output presentation, and HTTP artifact-containment policy. ## Quickstart @@ -21,8 +24,9 @@ go run ./cmd/scriptorium render \ --format json ``` -This command renders the prepared prompt and effective runtime settings without calling an LLM. -For complete invocation and output behavior, see the [CLI reference](docs/cli.md). +This renders the prepared prompt and effective runtime settings without calling +a model. For complete invocation and output behavior, see the +[CLI reference](docs/cli.md). ## Documentation @@ -31,15 +35,16 @@ For complete invocation and output behavior, see the [CLI reference](docs/cli.md - [HTTP API reference](docs/api.md) - [Operations guide](docs/operations.md) - [Consumer integration overview](docs/consumers/api.md) -- [Go library package](docs/consumers/pkg-scriptorium.md) - [Subprocess integration](docs/integrations/subprocess.md) -- [OpenAI-compatible chat integration](docs/integrations/openai-compatible-chat.md) - [Architecture policy](docs/policy/architecture.md) +- [Promptkit framework formats](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/formats.md) +- [Promptkit Go consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/consumers/pkg-promptkit.md) ## Examples -- [Minimal configuration](examples/config.yml) and [complete configuration](examples/config.full.yml) -- [Prompt definitions](examples/prompts/), [execution profiles](examples/profiles/), [schemas](examples/schemas/), and [synthetic input fixtures](examples/fixtures/) +- [Minimal configuration](examples/config.yml) and + [complete configuration](examples/config.full.yml) +- [Prompt definitions](examples/prompts/), [execution profiles](examples/profiles/), + [schemas](examples/schemas/), and [synthetic input fixtures](examples/fixtures/) - [Render script](examples/render-markdown-summary.sh) - [HTTP request](examples/http-run.json) -- [Go library example](examples/go-library/prepare/main.go) diff --git a/docs/api.md b/docs/api.md index cbcfcd9..942d333 100644 --- a/docs/api.md +++ b/docs/api.md @@ -66,11 +66,12 @@ untrusted writers. The optional `model` object accepts `endpoint`, `model`, `temperature`, `max_tokens`, `top_p`, `timeout_seconds`, `service_tier`, `reasoning_effort`, `api_key_env`, and `extra_params`. Numeric ranges and -credential supply are defined by the [configuration reference](config.md). +framework credential semantics are defined by the +[Promptkit format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/formats.md). Explicit zero values for the numeric fields are overrides; zero `timeout_seconds` disables the per-generation deadline only, retaining the request context and configured transport cap. The timeout layers are defined in -the [outbound integration contract](integrations/openai-compatible-chat.md#authentication-and-timeout). +the [Promptkit outbound integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/integrations/openai-compatible-chat.md#timeout-and-cancellation). Raw API-key values are not accepted. `api_key` and any other unknown model field cause `400 invalid_json`. diff --git a/docs/cli.md b/docs/cli.md index 44395eb..5458532 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -1,7 +1,7 @@ # CLI Reference This is the canonical contract for invoking Scriptorium. Configuration discovery, -precedence, directories, profiles, and schemas are defined in the +precedence, application source locations, and server settings are defined in the [configuration reference](config.md). The [HTTP API reference](api.md) owns service request and response behavior. @@ -69,7 +69,7 @@ only; the caller context and configured transport cap remain active. CLI durations are converted to whole seconds by truncation toward zero, so any duration whose absolute value is below one second becomes an explicit zero-second override. The timeout layers are defined in the -[outbound integration contract](integrations/openai-compatible-chat.md#authentication-and-timeout). +[Promptkit outbound integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/integrations/openai-compatible-chat.md#timeout-and-cancellation). There is no raw API-key flag. Use `--api-key-env`. diff --git a/docs/config.md b/docs/config.md index 3a98e97..0419897 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1,15 +1,17 @@ # Configuration Reference -This is the canonical reference for Scriptorium application settings and the -prompt, profile, and schema files those settings select. For command syntax, -see the [CLI reference](cli.md); for HTTP request shapes, limits, and outcomes, -see the [HTTP API reference](api.md). +This is the canonical reference for Scriptorium application settings. Prompt, +profile, schema, execution-setting, built-in profile, and framework credential +semantics are defined by the +[Promptkit v0.1.0 format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/formats.md). +For command syntax, see the [CLI reference](cli.md); for HTTP request shapes and +outcomes, see the [HTTP API reference](api.md). ## Discovery And Precedence Application settings are resolved in this order: -1. built-in defaults; +1. built-in Scriptorium defaults; 2. a configuration file; then 3. CLI overrides. @@ -19,7 +21,7 @@ If neither exists, it uses built-in defaults. An explicit `--config` path must exist and decode successfully. The maintained [minimal configuration](../examples/config.yml) and -[full configuration](../examples/config.full.yml) are copyable examples. +[complete configuration](../examples/config.full.yml) are copyable examples. ## Application Configuration File @@ -28,146 +30,57 @@ do not override a prior value. Raw API-key fields are not accepted. | Field | Default | Meaning | | --- | --- | --- | -| `prompt_dir` | unset | Directory containing prompt-definition YAML. `run`, `render`, and `serve` require an effective value. | -| `profile_dir` | unset | Directory containing custom profile YAML. Built-in profiles remain available. | -| `schema_dir` | `.` | Base directory for relative JSON Schema paths. | +| `prompt_dir` | unset | Promptkit prompt-definition source directory. `run`, `render`, and `serve` require an effective value. | +| `profile_dir` | unset | Optional custom Promptkit profile source directory overlaid on Promptkit built-ins. | +| `schema_dir` | `.` | Promptkit schema source directory for relative schema paths. | | `server.addr` | `:8080` | Address used by `serve`. | | `server.artifact_root` | unset | Root that enables HTTP `file` input references. | -| `server.max_request_bytes` | `16777216` | Maximum encoded HTTP request body bytes; `0` disables the limit. | +| `server.max_request_bytes` | `16777216` | Maximum encoded HTTP request-body bytes; `0` disables the limit. | | `server.max_artifact_bytes` | `16777216` | Maximum HTTP file-input artifact bytes; `0` disables the limit. | | `server.max_response_bytes` | `16777216` | Maximum encoded HTTP response bytes; `0` disables the limit. | -| `defaults.render_format` | `text` | Default `render` output format: `text` or `json`. | +| `defaults.render_format` | `text` | Default prepared-run output format: `text` or `json`. | -The three size fields must be zero or greater. The HTTP contract defines how -each limit is enforced and reported. `server.artifact_root` configures the -deployment boundary; see the [HTTP API reference](api.md) for request-path and -containment behavior, and [operations](operations.md) for deployment handling. +The size fields must be zero or greater. The [HTTP API](api.md) defines how +each limit is enforced and reported. `server.artifact_root` configures an HTTP +deployment boundary; see [operations](operations.md) for deployment handling. -## Prompt Definition Files +## Framework Source Mapping -Prompt definitions are strict YAML files anywhere below `prompt_dir`. A prompt -is selected by its YAML `id`, not by file path; nested directories are only for -organization. See [maintained prompt examples](../examples/prompts/). +Scriptorium passes `prompt_dir`, `profile_dir`, and `schema_dir` to Promptkit +when constructing its engine. Scriptorium does not redefine or independently +parse those framework file formats. -| Field | Required | Meaning | -| --- | --- | --- | -| `id` | yes | Prompt identifier. | -| `version` | yes | Prompt version. | -| `default_profile` | no | Profile used when a request omits a profile ID. | -| `description` | no | Human-readable description. | -| `session_id` | no | Go-template string rendered from request variables and sent to a compatible provider when non-empty. | -| `inputs` | no | Declared input metadata. | -| `messages` | yes | Chat-message templates. | -| `output` | yes | Output format and validation contract. | +- Prompt selection, versions, message templates, inputs, output contracts, and + session IDs are Promptkit contracts. +- Profile fields, numeric ranges, execution defaults, overlay precedence, + built-in profiles, and credential rules are Promptkit contracts. +- Schema path behavior and generated-content validation are Promptkit + contracts. -### Inputs And Messages +See the +[tagged Promptkit format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/formats.md) +for all of those definitions. The files under +[`examples/prompts`](../examples/prompts/), +[`examples/profiles`](../examples/profiles/), and +[`examples/schemas`](../examples/schemas/) are maintained Scriptorium +application inputs using that tagged format. -Each `inputs` item has a required `name` and optional `required`, -`content_type`, and `description` fields. Input names must be unique. +## Credentials And Outbound Behavior -Each message has a required `role`, exactly one of `content` or `content_file`, -and optional `cache_control`. A `content_file` path is relative to the prompt -file. `cache_control.type` must be `ephemeral`; its optional `ttl` is `1h`. +Scriptorium maps `--api-key-env` and HTTP `model.api_key_env` into Promptkit +request overrides. Keep secret values in environment variables and store only +their names in configuration or framework source files. Do not place raw keys +in configuration, prompts, profiles, CLI arguments, examples, or HTTP +payloads. -`session_id` uses the same template variables as messages. Empty rendered -values are omitted. A rendered value may contain at most 256 Unicode code -points. - -### Output Contract - -| Field | Required | Values or behavior | -| --- | --- | --- | -| `format` | yes | `text`, `markdown`, or `json`. | -| `validation_mode` | yes | `none`, `basic`, `json`, or `json_schema`. | -| `schema_path` | for `json_schema` | Schema path, relative to `schema_dir` unless absolute. | -| `repair_attempts` | no | Integer greater than or equal to `0`; omitted means `0`. | - -## Profile Definition Files - -Profiles are strict YAML files anywhere below `profile_dir`. A profile is -selected by YAML `id`; nested directories are organizational. See the -[maintained profile examples](../examples/profiles/). - -| Field | Required | Meaning | -| --- | --- | --- | -| `id` | yes | Profile identifier. | -| `endpoint` | yes | OpenAI-compatible base URL, including its API version path when needed. | -| `model` | yes | Provider model name. | -| `temperature` | no | Number from `0` through `2`. | -| `max_tokens` | no | Integer zero or greater. | -| `top_p` | no | Number from `0` through `1`. | -| `timeout_seconds` | no | Per-generation-call deadline in whole seconds; integer zero or greater. | -| `service_tier` | no | Non-empty provider-specific request tier. | -| `reasoning_effort` | no | Non-empty provider-specific reasoning setting. | -| `api_key_env` | no | Environment-variable name containing the API key. | -| `extra_params` | no | JSON-compatible provider-specific outbound request fields. | - -Execution defaults before profile and request overrides are `temperature: 0`, -`max_tokens: 0`, `top_p: 1`, and `timeout_seconds: 600`. Profile numeric values -merge by non-zero value. Request overrides preserve presence, so an explicit -zero can override a profile value. For `timeout_seconds`, explicit request zero -disables the generation deadline while retaining the caller context and the -built-in client's transport cap. See the -[OpenAI-compatible integration contract](integrations/openai-compatible-chat.md#authentication-and-timeout) -for the complete timeout interaction. - -Custom profiles take precedence over built-ins with the same ID. Invalid custom -profiles are errors; they do not fall back to a built-in profile. Raw `api_key` -is rejected. Use `api_key_env`, or the public Go package's request-scoped key -mechanism described in the [package contract](consumers/pkg-scriptorium.md). - -`extra_params` keys must be non-empty and cannot be `model`, `session_id`, -`messages`, `temperature`, `max_tokens`, `top_p`, `service_tier`, -`reasoning_effort`, or `response_format`. - -### Built-In Profile Catalog - -Each embedded profile uses `OPENROUTER_API_KEY`. - -| Provider | ID | Model | -| --- | --- | --- | -| aion-labs | `aion-2` | `aion-labs/aion-2.0` | -| anthropic | `claude-fable-latest` | `~anthropic/claude-fable-latest` | -| anthropic | `claude-haiku-latest` | `~anthropic/claude-haiku-latest` | -| anthropic | `claude-opus-latest` | `~anthropic/claude-opus-latest` | -| anthropic | `claude-sonnet-latest` | `~anthropic/claude-sonnet-latest` | -| deepseek | `deepseek-3-2` | `deepseek/deepseek-v3.2` | -| deepseek | `deepseek-4-flash` | `deepseek/deepseek-v4-flash` | -| deepseek | `deepseek-4-pro` | `deepseek/deepseek-v4-pro` | -| google | `gemini-2-flash` | `google/gemini-2.5-flash` | -| google | `gemini-2-flash-lite` | `google/gemini-2.5-flash-lite` | -| google | `gemini-2-pro` | `google/gemini-2.5-pro` | -| google | `gemini-3-flash-lite` | `google/gemini-3.1-flash-lite` | -| google | `gemini-flash-latest` | `~google/gemini-flash-latest` | -| google | `gemini-pro-latest` | `~google/gemini-pro-latest` | -| google | `gemma-4-31b` | `google/gemma-4-31b-it:exacto` | -| minimax | `minimax-m2` | `minimax/minimax-m2.5` | -| minimax | `minimax-m3` | `minimax/minimax-m3` | -| mistral | `mistral-large-2512` | `mistralai/mistral-large-2512` | -| mistral | `mistral-medium-3-5` | `mistralai/mistral-medium-3-5` | -| mistral | `mistral-small-3` | `mistralai/mistral-small-3.2-24b-instruct` | -| mistral | `mistral-small-4` | `mistralai/mistral-small-2603` | -| nvidia | `nemotron-3-ultra` | `nvidia/nemotron-3-ultra-550b-a55b` | -| openai | `gpt-5-mini` | `openai/gpt-5.4-mini` | -| openai | `gpt-5-nano` | `openai/gpt-5.4-nano` | - -## Schemas - -Schemas are JSON files, normally below `schema_dir`. `json_schema` output -requires a `schema_path`. Relative paths resolve from `schema_dir`; absolute -paths are used directly. Referenced nested schemas use relative paths and are -not discovered by basename. An unreadable or invalid schema is a runtime -validation error; generated content that fails JSON or schema validation is a -validation result. - -## Credentials - -Keep secrets in environment variables. Store only an environment-variable name -in `api_key_env`; do not place raw keys in configuration, prompt or profile -files, CLI arguments, examples, or HTTP payloads. +Promptkit's +[OpenAI-compatible integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/integrations/openai-compatible-chat.md) +defines outbound authentication, provider request mapping, transport limits, +and timeout layering. ## Related References - [CLI reference](cli.md) - [HTTP API reference](api.md) -- [OpenAI-compatible outbound contract](integrations/openai-compatible-chat.md) +- [Operations guide](operations.md) +- [Promptkit framework formats](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/formats.md) diff --git a/docs/consumers/api.md b/docs/consumers/api.md index c58d7d9..ff41182 100644 --- a/docs/consumers/api.md +++ b/docs/consumers/api.md @@ -1,45 +1,21 @@ # Consumer Integration Overview -This guide helps applications choose a Scriptorium interface and understand -their responsibilities. The linked contracts own interface syntax and wire -semantics. +Scriptorium exposes executable interfaces. Choose between a local subprocess +and the HTTP service according to the boundary your application needs. | Interface | Use when | | --- | --- | -| Go package | The consumer is Go and needs typed requests, results, or an injected LLM client. | -| CLI subprocess | The consumer needs process isolation or is not written in Go. | +| CLI subprocess | The consumer needs a synchronous local process boundary or prepared output. | | HTTP API | The consumer needs a service boundary or remote access. | -- Go package: [package contract](pkg-scriptorium.md) - CLI subprocess: [subprocess integration](../integrations/subprocess.md) - HTTP service: [HTTP API reference](../api.md) -- Prompt, profile, schema, and credential configuration: [configuration reference](../config.md) +- Application configuration: [configuration reference](../config.md) -## Minimal Go Use - -```go -engine, err := scriptorium.NewEngine(scriptorium.Config{ - PromptDir: "./examples/prompts", - ProfileDir: "./examples/profiles", -}) -if err != nil { - return err -} - -prepared, err := engine.Prepare(ctx, scriptorium.RunRequest{ - PromptID: "generic.markdown_summary", - Inputs: map[string]scriptorium.ArtifactRef{ - "transcript": scriptorium.File("./examples/fixtures/transcript.md"), - }, -}) -if err != nil { - return err -} -_ = prepared -``` - -For a maintained program, see -[`examples/go-library/prepare`](../../examples/go-library/prepare). +Go applications that need an in-process prompt framework should import +Promptkit directly. The tagged +[Promptkit Go consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/consumers/pkg-promptkit.md) +owns that interface; Scriptorium does not provide a Go library package. ## Consumer Responsibilities @@ -47,13 +23,14 @@ Consumers are responsible for: - selecting and deploying prompt, profile, and schema assets; - supplying required inputs and template variables; -- supplying credentials through the applicable interface; -- protecting rendered prompts and generated artifacts as potentially sensitive; +- supplying credentials through the chosen interface; +- protecting rendered prompts and generated artifacts as potentially + sensitive; - deciding whether validation-failed output is usable; and - retrying only when another model call is acceptable. -Scriptorium does not persist run state. A retry can produce different output and -can incur another provider request. CLI exit behavior belongs to the -[CLI reference](../cli.md); HTTP status behavior belongs to the -[HTTP API reference](../api.md); package errors and results belong to the -[package contract](pkg-scriptorium.md). +Scriptorium does not persist run state. A retry can produce different output +and can incur another provider request. CLI exits belong to the +[CLI reference](../cli.md), HTTP status behavior belongs to the +[HTTP API reference](../api.md), and framework semantics belong to +[Promptkit v0.1.0](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/formats.md). diff --git a/docs/consumers/pkg-scriptorium.md b/docs/consumers/pkg-scriptorium.md deleted file mode 100644 index ef71f30..0000000 --- a/docs/consumers/pkg-scriptorium.md +++ /dev/null @@ -1,203 +0,0 @@ -# Package `scriptorium` - -Import path: - -```go -import "gitea.maximumdirect.net/eric/scriptorium" -``` - -This is the canonical public Go contract for in-process prompt preparation and -execution. Prompt, profile, and schema file formats are defined in the -[configuration reference](../config.md). - -## Engine Construction - -`NewEngine(Config, ...Option)` constructs an engine. `Config` has these -fields: - -| Field | Meaning | -| --- | --- | -| `PromptDir` | Prompt-definition directory, required unless a prompt source option is supplied. | -| `ProfileDir` | Optional custom profile directory over built-ins. | -| `SchemaDir` | Schema directory; empty uses `.`. | -| `Timeout` | Transport-wide safety cap for the built-in OpenAI-compatible client when `HTTPClient` is absent or has a non-positive timeout. A non-positive value uses the internal ten-minute default. | -| `HTTPClient` | Optional HTTP client for that built-in client. It is cloned; a positive `Timeout` on it is the transport cap and takes precedence over `Config.Timeout`. A non-positive client timeout is treated as unset. | - -Nil options are ignored. Invalid construction, including -`WithLLMClient(nil)` and `WithArtifactReader(nil)`, returns an error matching -`ErrInvalidConfig`. - -Profile and request `timeout_seconds` values select a per-generation-call -deadline independently of the transport cap. An explicit request override of -zero disables that generation deadline only. The complete interaction with the -caller context is defined in the -[OpenAI-compatible integration contract](../integrations/openai-compatible-chat.md#authentication-and-timeout). - -Source options replace their matching directory source: - -- prompts: `WithPromptFS(fsys, root)`, `WithPromptFile(path)`; -- profiles: `WithProfileFS(fsys, root)`, `WithProfileFile(path)`, and - `WithProfiles(profiles...)`; -- schemas: `WithSchemaFS(fsys, root)`, `WithSchemaFile(path)`; and -- LLM client: `WithLLMClient(client)`; and -- artifact reader: `WithArtifactReader(reader)`. - -`fs.FS` prompt-content and schema paths stay inside their configured roots. -Single-file prompt and profile sources are selected by their YAML `id`, not -their file names. `WithPromptFile` resolves relative `content_file` paths from -the prompt file's directory. `WithSchemaFile` exposes its schema by the schema -file's base name. In-memory profiles take precedence over an explicit or -directory-backed profile source, which in turn takes precedence over built-ins. -File and filesystem sources use the format and credential rules in the -[configuration reference](../config.md). - -## Prepare And Run - -`Prepare(ctx, request)` resolves the prompt, profile, input artifacts, -validation contract, and rendered messages without calling an LLM. -`Run(ctx, request)` performs that preparation, calls the configured client, -and validates generated content. - -```go -engine, err := scriptorium.NewEngine(scriptorium.Config{ - PromptDir: "./examples/prompts", - ProfileDir: "./examples/profiles", -}) -if err != nil { - return err -} - -prepared, err := engine.Prepare(ctx, scriptorium.RunRequest{ - PromptID: "generic.markdown_summary", - Inputs: map[string]scriptorium.ArtifactRef{ - "transcript": scriptorium.File("./examples/fixtures/transcript.md"), - }, -}) -if err != nil { - return err -} -_ = prepared.Messages -``` - -The maintained package example is -[`examples/go-library/prepare`](../../examples/go-library/prepare). - -`PreparedRun` exposes prompt, selected-profile, effective-model, output -contract, structured-output, input-hash, rendered-message, and timing -information. It does not include a resolved API key, model output, validation -result, or target-presence metadata. - -`RunResult` adds run ID, artifact, raw output, validation, model metadata, -usage, and duration. Generated-content validation failures return a result with -`Validation.Status == ValidationFailed`; schema or validator runtime failures -return an error matching `ErrValidation`. - -## Public Values - -`ArtifactRef` has `Type`, `URI`, and `Body`; `Artifact` has `Name`, -`ContentType`, `Body`, `URI`, `Size`, and `Hash`. `ExecutionTarget` exposes the -effective endpoint, model, numeric settings, credential-environment name, -service tier, reasoning effort, and extra parameters. `ValidationResult` -contains status, mode, errors, schema path, repair attempts, and validity. - -The exported constants define these serialized values: - -- artifact types: `inline` and `file`; -- output formats: `text`, `markdown`, and `json`; -- validation modes: `none`, `basic`, `json`, and `json_schema`; and -- validation statuses: `passed`, `failed`, and `skipped`. - -`TokenUsage` reports prompt, completion, total, cached, and cache-write token -counts. `RenderedPrompt`, `RenderedMessage`, `CacheControl`, and -`StructuredOutputSpec` are the public shapes used by injected LLM clients. - -`ArtifactReader` implements -`Read(context.Context, ArtifactRef) (*Artifact, error)`. Supplying it through -`WithArtifactReader` replaces, rather than extends, the engine's default inline -and file reader for every input. Omitting the option retains that default; -`WithArtifactReader(nil)` makes engine construction fail with -`ErrInvalidConfig`. - -Reader failures are surfaced as errors matching `ErrArtifactLoad` while -preserving the reader's original error identity for `errors.Is`. A `(nil, nil)` -reader response is also an artifact-load failure. Readers are responsible for -artifact metadata, although the engine assigns the input-map name when the -returned name is empty; readers should not retain or mutate caller values. - -## Requests, Inputs, And Overrides - -`RunRequest` fields are `PromptID`, `PromptVersion`, `ProfileID`, -`APIKey`, `Inputs`, `Vars`, `Execution`, `Validation`, and -`Metadata`. - -Input helpers are: - -- `File(path)` for a file-backed artifact; -- `Inline(body)` for inline content; and -- `InlineWithURI(uri, body)` for inline content with URI metadata. - -Required declared inputs must be supplied. Template rendering must also resolve -every input name the prompt actually references. Extra entries in `Inputs` -are not rejected solely because they are undeclared. - -`ExecutionTargetOverride` supplies endpoint, model, credential-environment, -service-tier, reasoning-effort, and extra-parameter overrides. Its numeric -fields (`Temperature`, `MaxTokens`, `TopP`, and `TimeoutSeconds`) are -pointers so explicit zero values are preserved. `OutputContract` supplies -`Format`, `ValidationMode`, `SchemaPath`, and `RepairAttempts`. - -`ExtraParams` accepts JSON-compatible values: strings, booleans, finite -numbers, objects with string keys, arrays or slices, and nil. Unsupported -values, non-string map keys, non-finite floats, and cycles return -`ErrInvalidConfig` for profiles or `ErrInvalidRequest` for request -overrides. - -## Profiles And Credentials - -`OpenAICompatibleProfile(OpenAICompatibleProfileConfig)` creates an -in-memory `Profile`. Its public fields are `ID`, `Endpoint`, `Model`, -`Temperature`, `MaxTokens`, `TopP`, `TimeoutSeconds`, `ServiceTier`, -`ReasoningEffort`, `APIKeyRequired`, and `ExtraParams`. -`WithProfiles` rejects duplicate IDs in one call. - -A direct `RunRequest.APIKey` is request-scoped and takes precedence over -`api_key_env` for the built-in client. It is excluded from JSON output and -from `PreparedRun` and `RunResult`. The package's `String` and -`GoString` methods report only whether a direct key is set. Do not use -reflection-based dumps of request structs, which can bypass that redaction. - -## Injected LLM Clients - -`LLMClient` implements: - -```go -Generate(context.Context, GenerateRequest) (*GenerateResponse, error) -``` - -Injected clients receive the rendered prompt, effective execution target, numeric -target-presence metadata, optional structured-output specification, and direct -request API key. `GenerateResponse` returns content and `TokenUsage`. -Custom clients should avoid logging raw prompts or credentials. - -## Errors - -Public methods preserve these sentinel checks through `errors.Is`: - -- `ErrInvalidConfig` -- `ErrInvalidRequest` -- `ErrPromptNotFound` -- `ErrProfileNotFound` -- `ErrProfileRequired` -- `ErrPromptLoad` -- `ErrProfileLoad` -- `ErrAPIKeyEnvMissing` -- `ErrArtifactLoad` -- `ErrPromptRender` -- `ErrLLMGenerate` -- `ErrValidation` - -`ErrProfileRequired` and `ErrAPIKeyEnvMissing` each also match -`ErrInvalidRequest`, so callers can select either the broad request category or -the specific condition. - -For the HTTP interface, see the [HTTP API reference](../api.md). diff --git a/docs/development.md b/docs/development.md index 378e9d4..392de98 100644 --- a/docs/development.md +++ b/docs/development.md @@ -1,63 +1,56 @@ # Development -This is the contributor entry point for Scriptorium. Use the task-specific -reading guide below before making changes. Canonical architecture, contracts, -component behavior, and policies remain in their owning documents. +This is the contributor entry point for Scriptorium. Scriptorium is an +application that consumes the public +[Promptkit v0.1.0 package](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/consumers/pkg-promptkit.md); +framework implementation work belongs in Promptkit. ## Initial Orientation Before starting work: 1. inspect the working tree and preserve unrelated changes; -2. read the architecture policy for code or design work; -3. read the policy, contract, and internal documents listed for the task; -4. inspect the relevant implementation and tests before deciding how to change - them. +2. read the [architecture policy](policy/architecture.md); +3. follow the task-specific contracts and internal documents below; and +4. inspect the relevant implementation and tests before changing them. -Start with: - -- [Architecture policy](policy/architecture.md) for system boundaries, - invariants, and non-goals; -- [Internal component overview](internal/overview.md) for the current package - and component map; -- [Documentation policy](policy/documentation.md) before changing - documentation; -- [Testing policy](policy/testing.md) before adding, rewriting, or deleting - tests. +Also read the [documentation policy](policy/documentation.md) before changing +documentation and the [testing policy](policy/testing.md) before changing +tests. ## Task-Specific Reading Guide | Task | Read before changing | | --- | --- | | Repository orientation or component responsibility | [Internal component overview](internal/overview.md) and [architecture policy](policy/architecture.md) | -| Public Go package or engine behavior | [Go package consumer contract](consumers/pkg-scriptorium.md), [internal component overview](internal/overview.md), [runner internals](internal/runner.md), [adapter internals](internal/adapters.md), and [source internals](internal/sources.md) | -| CLI commands, flags, output, or exit behavior | [CLI contract](cli.md), [internal component overview](internal/overview.md), and [adapter internals](internal/adapters.md) | -| HTTP routes, DTOs, limits, or status mapping | [HTTP API contract](api.md), [internal component overview](internal/overview.md), [adapter internals](internal/adapters.md), and [source internals](internal/sources.md) | -| Application configuration | [Configuration contract](config.md), [internal component overview](internal/overview.md), [adapter internals](internal/adapters.md), and [source internals](internal/sources.md) | -| Prompt, profile, schema, or artifact loading | [Configuration contract](config.md), [internal component overview](internal/overview.md), and [source internals](internal/sources.md) | -| Runner orchestration, rendering, validation, or repair | [Runner internals](internal/runner.md) and [source internals](internal/sources.md) | -| OpenAI-compatible request or response behavior | [OpenAI-compatible integration](integrations/openai-compatible-chat.md), [LLM internals](internal/llm.md), [runner internals](internal/runner.md), and [adapter internals](internal/adapters.md) | +| CLI commands, flags, output, or exit behavior | [CLI contract](cli.md) and [adapter internals](internal/adapters.md) | +| HTTP routes, DTOs, limits, status mapping, or artifact policy | [HTTP API contract](api.md), [adapter internals](internal/adapters.md), and [source internals](internal/sources.md) | +| Application configuration or precedence | [Configuration contract](config.md), [adapter internals](internal/adapters.md), and [source internals](internal/sources.md) | +| Prepared-run presentation | [CLI contract](cli.md), [adapter internals](internal/adapters.md), and `internal/format` | +| Prompt, profile, schema, generation, or validation semantics | [Promptkit framework formats](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/formats.md) and the [Promptkit consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/consumers/pkg-promptkit.md) | +| OpenAI-compatible outbound behavior or timeout layering | [Promptkit integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/integrations/openai-compatible-chat.md) | | Subprocess behavior | [Subprocess integration](integrations/subprocess.md) and [CLI contract](cli.md) | | Runtime operation or recovery | [Operations](operations.md) | -| Examples or copyable assets | The owning contract for the demonstrated behavior and the related files under `examples/` | -| Architecture decisions or future work | The [documentation policy](policy/documentation.md), relevant accepted ADRs such as [ADR 0001](adr/0001-adopt-canonical-documentation-ownership.md), and relevant roadmap documents under `roadmap/` | +| Release packaging | `.woodpecker/release.yml`, [operations](operations.md), and the architecture policy | +| Examples or copyable assets | The owning Scriptorium contract, the relevant [Promptkit format contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/formats.md), and the related files under `examples/` | +| Architecture decisions or future work | The [documentation policy](policy/documentation.md), relevant accepted ADRs, and relevant roadmap documents | -For cross-cutting changes, follow every applicable row. Internal component -documents own detailed subsystem change recipes. +Cross-project changes land and release in Promptkit before Scriptorium adopts +the tagged version. Do not commit a Go workspace, local replacement, vendored +Promptkit source, or an import of a Promptkit `internal` package. ## Baseline Validation -Use focused checks while iterating, then run validation proportionate to the -change and the risks described by the testing policy. - -The repository-level baseline for code changes is: +For code changes, run: ```bash go test ./... +go test -race ./... go vet ./... go build ./cmd/scriptorium ``` -Documentation-only work does not require the full Go suite unless it changes -commands, examples, generated output, or another behavior that the suite -validates. Always check changed links, paths, examples, and canonical ownership. +Check formatting with `gofmt`, run `git diff --check`, and validate affected +examples and documentation links. Documentation-only work does not require +unrelated new tests, but commands and examples changed by documentation must be +run. diff --git a/docs/integrations/openai-compatible-chat.md b/docs/integrations/openai-compatible-chat.md deleted file mode 100644 index 1420d10..0000000 --- a/docs/integrations/openai-compatible-chat.md +++ /dev/null @@ -1,121 +0,0 @@ -# OpenAI-Compatible Chat Integration - -This is the outbound wire contract for Scriptorium's OpenAI-compatible -chat-completions client. - -## Endpoint And Method - -Scriptorium uses the request endpoint override when present; otherwise it uses -the configured client base URL. It removes a trailing slash and sends -`POST /chat/completions`. - -For example, `http://localhost:8000/v1` becomes -`http://localhost:8000/v1/chat/completions`. - -## Request Payload - -The payload always contains `model` and rendered `messages`. It additionally -contains these fields when applicable: - -| Field | Inclusion | -| --- | --- | -| `session_id` | Non-empty rendered prompt session ID. | -| `temperature` | Non-zero effective value or an explicit zero override. | -| `max_tokens` | Non-zero effective value or an explicit zero override. | -| `top_p` | Non-zero effective value or an explicit zero override. | -| `service_tier` | Any non-empty configured value. | -| `reasoning_effort` | Any non-empty configured value. | -| `response_format` | Structured output is requested. | -| provider-specific fields | Flattened from `extra_params`. | - -`service_tier` and `reasoning_effort` are forwarded without a provider value -catalog; the selected backend decides which values it supports. - -`extra_params` are top-level JSON fields, not a nested object. Keys cannot be -empty or collide with `model`, `session_id`, `messages`, `temperature`, -`max_tokens`, `top_p`, `service_tier`, `reasoning_effort`, or -`response_format`. Values must be JSON-serializable. - -A rendered `session_id` is sent as a top-level JSON field, not as a header. -Empty values are omitted. The maximum length is 256 Unicode code points. - -Messages without cache control use string `content`. A message with cache -control uses one text block: - -```json -{ - "role": "system", - "content": [{ - "type": "text", - "text": "rendered text", - "cache_control": {"type": "ephemeral", "ttl": "1h"} - }] -} -``` - -When the prompt omits cache-control `ttl`, the payload omits `ttl`. -Structured JSON Schema output is sent as: - -```json -{ - "response_format": { - "type": "json_schema", - "json_schema": { - "name": "schema name", - "strict": true, - "schema": {"type": "object"} - } - } -} -``` - -## Authentication And Timeout - -When a direct request API key is present, Scriptorium sends -`Authorization: Bearer ` and does not read `api_key_env`. Otherwise, it -resolves the configured non-empty `api_key_env` at request time and sends the -same header. If neither mechanism supplies a key, it sends no -`Authorization` header. - -The transport-wide safety cap is chosen at client construction. A positive -timeout on a supplied `http.Client` takes precedence over a positive -`Config.Timeout`; if neither is positive, the internal ten-minute default is -used. The supplied client is cloned, and zero or negative timeout values are -treated as unset. - -Separately, a positive effective `timeout_seconds` creates a deadline for each -outbound generation call. Its value follows the execution-setting hierarchy: -an explicit request override, then a non-zero profile value, then the -600-second framework default. An explicit request override of zero disables -only this generation deadline. Negative values are rejected before a request -is sent. - -The complete observable rule is that the earliest caller-context deadline, -transport cap, or positive generation deadline terminates the call. Transport -and cancellation failures retain the generation-error classification. - -## Response Subset And Failures - -A successful provider response must supply non-empty -`choices[0].message.content`. Scriptorium reads these optional or required -usage fields when present: - -- `usage.prompt_tokens` -- `usage.completion_tokens` -- `usage.total_tokens` -- `usage.prompt_tokens_details.cached_tokens` -- `usage.cache_write_tokens` - -Missing cache usage is reported as zero. Invalid JSON, an empty choices array, -or empty first-choice content is a malformed provider response. Network and -request-construction failures, non-2xx responses, and malformed responses fail -the outbound call. Provider response bodies are not exposed by this client. - -The client does not implement built-in retries, tool calls, top-level -`cache_control`, or multi-request payload modes. - -## Related References - -Prompt schema preparation and runner orchestration are described in -[runner internals](../internal/runner.md). Prompt and profile configuration is -defined by the [configuration reference](../config.md). diff --git a/docs/internal/adapters.md b/docs/internal/adapters.md index bbdbcb0..5a50d4d 100644 --- a/docs/internal/adapters.md +++ b/docs/internal/adapters.md @@ -2,115 +2,86 @@ ## Purpose -Adapters translate external inputs into public engine requests and translate -public results or errors back to their interface. They own IO and presentation -mechanics; use-case decisions remain behind the root `scriptorium` facade. +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), [HTTP API -reference](../api.md), and [Go package contract](../consumers/pkg-scriptorium.md). +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.1.0/docs/consumers/pkg-promptkit.md). ## Components And Collaborators - `cmd/scriptorium` passes process arguments and streams to `internal/adapter/cli`. -- `internal/adapter/cli` parses commands, resolves application settings through - `internal/config`, constructs the public engine, and owns process output - handling. -- `internal/adapter/http` decodes DTOs, maps them to public run requests, - calls its local public `Runner` interface, and maps public errors and results - to HTTP DTOs. -- The root `scriptorium` package maps its public types and options to internal - collaborators and maps selected internal errors to public sentinels. -- `internal/format` formats public prepared runs for the 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/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. ## Wiring Flows ### CLI -The CLI resolves configuration before constructing the public engine. `run` -calls `Engine.Run` with a public request and `render` calls `Engine.Prepare` -with the same request mapping. `serve` constructs the HTTP-owned restricted -artifact reader, injects it with `WithArtifactReader`, passes the resulting -engine directly to the HTTP handler, and starts the server. +`run` calls `promptkit.Engine.Run`; `render` calls +`promptkit.Engine.Prepare`. Both share request mapping for prompt/profile +selection, file inputs, variables, and presence-aware execution overrides. +Omitted framework settings remain zero values so Promptkit resolves its own +defaults. -Parser state records whether numeric runtime values were explicitly supplied. -That presence is carried into `scriptorium.ExecutionTargetOverride`, allowing -the engine to distinguish omitted values from explicit zero overrides. +`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. ### HTTP -The handler first enforces transport limits, strict JSON decoding, and the -minimal request shape. It maps DTO values to public types without deciding -prompt selection, source behavior, or validation semantics. On success it maps -the public result to the response DTO; on failure it uses `errors.Is` over -public framework errors and HTTP-local artifact-policy errors to choose the -public error mapping. +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 [HTTP API reference](../api.md) owns the route, DTO schema, status codes, -and externally observable limit behavior. - -### Public Go Facade - -`NewEngine` applies public options, selects filesystem, `fs.FS`, single-file, -or in-memory dependencies, and constructs a runner. The conversion functions -copy maps and slices across the boundary so callers do not receive internal -domain values. The facade maps selected internal errors to the public sentinel -set and keeps direct request API keys out of public results. +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. ## Package-Local Guarantees -- Adapters do not embed framework orchestration or source-loading decisions. -- Configuration is resolved before adapter dependency composition. -- CLI and HTTP consume the public engine without a repairer; a repairer remains - available only through explicit internal runner construction. -- DTO conversion preserves explicit numeric-override presence. -- Error mapping matches error identities, not error text. -- No adapter creates durable run state; caller-selected output files are not - application state. +- 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. -## Failure And Verification Boundaries +## Verification -Keep external error payloads concise, preserve strict external decoding, and do -not serialize resolved secret values. Validation content failures remain result -state; runtime failures remain errors for the relevant adapter to map. - -Inspect focused tests when changing this area: +Inspect: - `internal/adapter/cli/run_test.go` - `internal/adapter/http/handler_test.go` -- `engine_test.go` +- `internal/adapter/http/artifact_reader_test.go` - `internal/format/prepared_run_test.go` +- `internal/adapter/dependency_test.go` -Run the affected adapter package tests and recheck the relevant canonical -contract. The [testing policy](../policy/testing.md) owns global test -sufficiency guidance. +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 -### Application Configuration Fields +For a CLI or HTTP change: -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 affected external - contract. +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. -### CLI Flags - -1. Add the flag to the relevant parser 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 affected maintained examples. - -### Adapter Capabilities - -1. Define or reuse an adapter-local consumer interface with public facade - types when a test seam is needed. -2. Implement translation and IO behavior without moving framework decisions out - of the public engine. -3. Add focused mapping, parsing, and error-behavior tests. -4. Update this document and the affected public or integration contract. Update - [source internals](sources.md) when source-loading behavior changes. +Update [source internals](sources.md) when application source locations or HTTP +artifact containment changes. diff --git a/docs/internal/llm.md b/docs/internal/llm.md deleted file mode 100644 index ff8bab1..0000000 --- a/docs/internal/llm.md +++ /dev/null @@ -1,86 +0,0 @@ -# LLM Internals - -## Purpose - -`internal/llm` defines the provider-neutral `Client` interface and the -OpenAI-compatible client implementation. The [OpenAI-compatible integration -contract](../integrations/openai-compatible-chat.md) owns the outbound HTTP wire -format and protocol behavior. - -## Construction - -`NewOpenAICompatibleClient` validates a non-empty configured base URL, records -an optional default model, and resolves one transport cap. A supplied client -with a positive timeout supplies that cap; otherwise a positive configured -timeout is used, then the internal default. - -When callers supply an `http.Client`, construction clones it rather than -mutating the caller's instance. A supplied client with a zero or negative -timeout receives the resolved transport cap in the clone. The client stores the -trimmed base URL, default model, and cloned client. - -## Generate Flow - -`Generate` receives a `domain.GenerateRequest` from the runner: - -1. validate the effective timeout and choose the request endpoint; -2. map the domain request to the internal wire-request representation; -3. validate and flatten extra parameters and encode JSON; -4. derive a child context when the effective generation timeout is positive, - then create the HTTP request with that context; -5. prefer a direct API key, otherwise resolve the configured key environment - variable; -6. execute with the construction-time HTTP client, reject non-success status - responses without returning - provider response bodies; and -7. decode the response subset into `domain.GenerateResponse`. - -`openAIChatRequestFromGenerateRequest` is the conversion boundary for effective -model defaults, explicit numeric-presence state, rendered messages, structured -output, and session-ID validation. `openAIChatRequestPayload` protects reserved -fields and JSON encoding before an HTTP call. The external payload shape is -defined only in the [integration contract](../integrations/openai-compatible-chat.md). - -## Error Categories - -The package uses these internal sentinels: - -- `ErrInvalidConfig` for invalid client construction; -- `ErrInvalidRequest` for invalid effective generation input; -- `ErrRequestFailed` for request construction or transport failures; -- `ErrUnexpectedStatus` for non-success HTTP responses; and -- `ErrMalformedResponse` for invalid or incomplete successful-response data. - -The runner maps an invalid LLM request to its invalid-request category and -other LLM failures to its generation category. Adapters then apply their public -error contracts. - -## Package-Local Guarantees - -- The default-model fallback happens before wire encoding. -- Per-generation timeout handling derives a request context; it never replaces - or mutates the configured HTTP client's transport cap. -- Direct API keys take precedence over environment lookup within this client. -- Provider response bodies are discarded for non-success status responses. -- The client does not implement retries, tool calls, or a stateful session - store. - -## Verification And Change Recipe - -Inspect: - -- `internal/llm/openai_compatible_client_test.go` -- `internal/usecase/runner_test.go` -- `internal/adapter/http/handler_test.go` - -When changing the client: - -1. keep domain-to-wire mapping inside `internal/llm` and preserve the `Client` - interface; -2. test construction, timeout selection, mapping, and error categorization; -3. update the [OpenAI-compatible integration contract](../integrations/openai-compatible-chat.md) - for any observable wire or protocol change; and -4. update [runner internals](runner.md) if the client boundary or structured - output handoff changes. - -The [testing policy](../policy/testing.md) owns global test sufficiency. diff --git a/docs/internal/overview.md b/docs/internal/overview.md index 2b5b72d..87d6799 100644 --- a/docs/internal/overview.md +++ b/docs/internal/overview.md @@ -1,48 +1,18 @@ # Internal Component Overview -## Purpose - -This is the inventory of Scriptorium's implemented components for contributors. -The [architecture policy](../policy/architecture.md) owns normative boundaries -and invariants; public behavior belongs in the linked contracts. - -## Public And Command Entrypoints +This is the complete inventory of Scriptorium's implemented Go components. +The [architecture policy](../policy/architecture.md) owns normative boundaries; +public behavior belongs in the linked contracts. | Component | Implemented responsibility | References | | --- | --- | --- | -| Root package `scriptorium` | Public Go facade that constructs the engine, exposes request/result types and options, and maps internal errors. | [Go package contract](../consumers/pkg-scriptorium.md), [adapter internals](adapters.md) | -| `cmd/scriptorium` | Process entrypoint that delegates command execution to the CLI adapter. | [CLI contract](../cli.md), [adapter internals](adapters.md) | +| `cmd/scriptorium` | Process entrypoint that delegates arguments and streams to the CLI adapter. | [CLI contract](../cli.md), [adapter internals](adapters.md) | +| `internal/adapter/cli` | Parses commands, resolves application settings, constructs Promptkit engines, maps requests, and owns process output and exit behavior. | [CLI contract](../cli.md), [adapter internals](adapters.md) | +| `internal/adapter/http` | Owns routes, DTOs, strict decoding, limits, Promptkit request/result mapping, public error mapping, and restricted HTTP artifact reading. | [HTTP API](../api.md), [adapter internals](adapters.md), [source internals](sources.md) | +| `internal/config` | Discovers and strictly decodes application configuration and applies built-in and CLI precedence. | [configuration contract](../config.md), [adapter internals](adapters.md) | +| `internal/defaults` | Holds Scriptorium-owned application and HTTP defaults. | [configuration contract](../config.md) | +| `internal/format` | Formats Promptkit prepared-run values for CLI text or JSON output. | [CLI contract](../cli.md), [adapter internals](adapters.md) | -## Adapters, Domain, And Use Case - -| Component | Implemented responsibility | References | -| --- | --- | --- | -| `internal/adapter/cli` | Parses CLI commands, constructs the public engine from application settings, and handles process input and output. | [CLI contract](../cli.md), [adapter internals](adapters.md) | -| `internal/adapter/http` | Maps HTTP requests and responses through public engine values, maps public errors, and owns restricted HTTP artifact policy. | [HTTP API contract](../api.md), [adapter internals](adapters.md) | -| `internal/domain` | Defines core request, result, output-contract, and LLM-boundary types. | [runner internals](runner.md) | -| `internal/usecase` | Implements `Runner` preparation, execution, validation coordination, and the repairer boundary. | [runner internals](runner.md) | - -## Configuration And Sources - -| Component | Implemented responsibility | References | -| --- | --- | --- | -| `internal/config` | Loads application settings, applies defaults, and applies CLI overrides. | [configuration contract](../config.md), [adapter internals](adapters.md) | -| `internal/defaults` | Holds compile-time default values used when application settings are resolved. | [configuration contract](../config.md) | -| `internal/promptdef` | Loads prompt definitions from filesystem and `fs.FS` sources. | [configuration contract](../config.md), [source internals](sources.md) | -| `internal/profile` | Loads filesystem and `fs.FS` execution profiles and combines profile repositories. | [configuration contract](../config.md), [source internals](sources.md) | -| `internal/profile/builtin` | Provides embedded built-in execution profiles as a repository. | [configuration contract](../config.md), [source internals](sources.md) | -| `internal/filecatalog` | Provides shared YAML discovery and source-root helpers. | [source internals](sources.md) | -| `internal/artifact` | Provides the framework's ordinary inline and unrestricted file artifact reader. | [configuration contract](../config.md), [source internals](sources.md) | -| `internal/prompt` | Renders prompt templates into messages. | [runner internals](runner.md) | - -## Formatting, Validation, And Model Access - -| Component | Implemented responsibility | References | -| --- | --- | --- | -| `internal/format` | Formats public prepared-run information for CLI output. | [CLI contract](../cli.md), [adapter internals](adapters.md) | -| `internal/validate` | Defines validation interfaces and provides standard filesystem and `fs.FS` schema validation. | [configuration contract](../config.md), [source internals](sources.md), [runner internals](runner.md) | -| `internal/llm` | Defines the provider-neutral LLM client boundary and its OpenAI-compatible implementation. | [OpenAI-compatible integration](../integrations/openai-compatible-chat.md), [LLM internals](llm.md), [runner internals](runner.md) | - -Focused internal documents describe the components that have detailed -orchestration, adapter, or source behavior. Package tests live alongside the -implementation and are identified in those focused documents where relevant. +Framework implementation packages are provided by +[Promptkit v0.1.0](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/consumers/pkg-promptkit.md) +and are not part of this repository. diff --git a/docs/internal/runner.md b/docs/internal/runner.md deleted file mode 100644 index b4e1378..0000000 --- a/docs/internal/runner.md +++ /dev/null @@ -1,120 +0,0 @@ -# Runner Internals - -## Purpose - -`internal/usecase.Runner` is the prompt-execution orchestrator. It prepares -domain requests, invokes an injected LLM client, validates output, and returns -domain results. Transport parsing, response mapping, and public type conversion -remain outside this package. - -The [configuration reference](../config.md) owns prompt, profile, schema, and -runtime-setting definitions. Public error behavior is defined by the -[HTTP API](../api.md) and [Go package](../consumers/pkg-scriptorium.md) -contracts. - -## Dependencies And Construction - -`Runner` receives these collaborators: - -- `promptdef.Repository`; -- `profile.Repository`; -- `artifact.Reader`; -- `prompt.Renderer`; -- `llm.Client`; -- `validate.Validator`; and -- an optional `OutputRepairer`. - -`NewRunner` constructs a runner without a repairer. `NewRunnerWithRepairer` -accepts one explicitly. The public engine chooses concrete repositories and -readers; executable adapters reach the runner only through that engine. The -runner does not load application configuration. - -## Prepare Flow - -`Prepare` performs one deterministic preparation pass for a request: - -1. validate the prompt ID and load the prompt definition; -2. hash the definition and select the explicit or default profile; -3. load the profile and resolve effective execution settings; -4. validate endpoint, model, and credential availability; -5. resolve the output contract and, for JSON Schema output, load a structured - schema document before model execution; -6. read and hash input artifacts; -7. render messages and the session ID; and -8. return a `PreparedRun` containing the effective state and rendered-prompt - hash. - -Execution settings merge defaults, profile values, and a request override. -Numeric override presence is retained so explicit zero values are not confused -with omissions. - -## Run And Validation Flow - -`Run` creates a run ID and timestamps, then calls `Prepare` rather than -duplicating preparation. It sends the prepared prompt, effective target, -target-presence state, and optional structured-output specification to the LLM -client. It converts the returned content to an output artifact, validates it, -and returns the artifact, validation, hashes, usage, and timing metadata. - -A validator can return a content result or an operational error. Content -failures stay in the result; schema loading, compilation, and validator -operational failures are returned as `ErrValidation`. The canonical distinction -for callers is documented by the public contracts. - -## Repair Boundary - -Repair is an internal optional loop. It starts only when a repairer is present, -the output contract permits one or more attempts, validation failed, and the -validation mode is JSON or JSON Schema. Each repair receives the previous -output, validation errors, effective target, structured-output specification, -and attempt metadata; every repaired result is validated again. - -`NewDefaultOutputRepairer` delegates to the injected LLM client. The public -engine, and therefore CLI and HTTP, uses `NewRunner` and does not inject this -repairer. - -## Error Translation - -Runner sentinels identify failure categories for adapters: - -- `ErrInvalidRequest` -- `ErrProfileRequired` -- `ErrAPIKeyEnvMissing` and `ErrAPIKeyRequired` -- `ErrPromptLoad`, `ErrProfileLoad`, and `ErrArtifactLoad` -- `ErrPromptRender` -- `ErrLLMGenerate` -- `ErrValidation` - -Wrap errors with those sentinels and preserve their identities through -`errors.Is`; adapters must not classify errors by message text. The runner -passes direct keys only to the LLM boundary and never includes resolved key -values in prepared or run results. - -## Package-Local Guarantees - -- `Run` always reuses `Prepare`. -- Schema documents are loaded before the initial LLM call when structured output - is required. -- Output validation records attempts used, including repair attempts. -- Runner state is per request; the package does not create a durable run store - or manifest. -- Source, renderer, validator, and LLM implementations remain injected - boundaries. - -## Verification And Change Recipe - -Inspect: - -- `internal/usecase/runner_test.go` -- `engine_test.go` - -When changing orchestration: - -1. identify the collaborator boundary and the affected `Prepare` or `Run` state; -2. preserve the `Run`-through-`Prepare` path and error identity; -3. add focused runner or integration tests for changed state transitions, - validation, or repair behavior; and -4. update the owning external contract and any affected source or LLM internal - document. - -The [testing policy](../policy/testing.md) owns global test sufficiency. diff --git a/docs/internal/sources.md b/docs/internal/sources.md index 51b08ea..925e999 100644 --- a/docs/internal/sources.md +++ b/docs/internal/sources.md @@ -2,98 +2,67 @@ ## Purpose -This document describes how source packages load prompt definitions, profiles, -schemas, and artifacts. The [configuration reference](../config.md) owns their -user-facing formats and settings. The [HTTP API reference](../api.md) owns -HTTP-visible artifact outcomes; [operations](../operations.md) owns deployment -handling. +This document covers Scriptorium-owned source locations and the restricted HTTP +artifact reader. Prompt, profile, schema, and ordinary artifact semantics are +owned by the tagged +[Promptkit format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/formats.md). -## Prompt Definitions +## Application Source Locations -`internal/promptdef` provides filesystem and `fs.FS` repositories. Both use -`internal/filecatalog` for recursive YAML discovery, deterministic ordering, -display paths, and root cleaning. +`internal/config` resolves `prompt_dir`, `profile_dir`, and `schema_dir` from +Scriptorium defaults, configuration files, and CLI overrides. +`internal/adapter/cli` passes those paths into `promptkit.Config` when +constructing the engine. -Repositories select a prompt by YAML ID and optional version rather than by -path. They decode through strict YAML handling, reject duplicate matching -definitions, and resolve `content_file` relative to the definition. The `fs.FS` -implementation resolves content paths inside its source root; absolute paths and -traversal outside that root are rejected before file access. +Scriptorium does not search, parse, validate, or overlay framework source files +itself. Promptkit owns prompt selection, profile built-ins and overlays, schema +resolution, ordinary file artifacts, and the related error identities. -## Profiles And Built-Ins +The [configuration reference](../config.md) owns Scriptorium's source-location +fields and precedence. Maintained files under `examples/` are application +inputs that use Promptkit's tagged formats. -`internal/profile` provides filesystem, `fs.FS`, and overlay repositories. -`internal/profile/builtin` exposes embedded assets through the same repository -interface. +## Restricted HTTP Artifact Reader -An overlay asks its primary source first. It falls back only when the primary -reports `ErrProfileNotFound`; invalid YAML, duplicate IDs, validation failures, -and raw-key failures are returned rather than hidden by fallback. This makes a -custom ID override a built-in ID while retaining errors in the custom source. +`internal/adapter/http` implements `promptkit.ArtifactReader` for HTTP +requests. The `serve` path injects it with +`promptkit.WithArtifactReader`, replacing Promptkit's ordinary reader for +inbound HTTP inputs. -The public engine can overlay in-memory profiles ahead of both file-backed and -built-in repositories. Profile field definitions, validation ranges, and the -built-in catalog remain in the [configuration reference](../config.md). +The reader: -## Schemas +- accepts inline references without an artifact root; +- denies file references when no root is configured; +- resolves relative paths below the configured root; +- accepts absolute paths only when they are lexically within that root; +- rejects lexical traversal outside the root; +- applies the configured file byte limit, with zero meaning unlimited; +- preserves content type, body, size, hash, name, and URI metadata; and +- honors context cancellation. -`internal/validate` supplies `StandardValidator` for filesystem sources and -`FSValidator` for `fs.FS` sources. Directory-backed validation loads the named -schema path; it does not search directories by basename. `fs.FS` schema paths -are cleaned and checked against their configured root, while a single-file -source matches its file base name. +Containment is lexical and does not resolve symlinks. The operating system +follows symlinks after the check. The [HTTP API](../api.md) owns observable +request outcomes, and [operations](../operations.md) owns safe deployment +permissions and root selection. -The runner requests a schema document before generation when it needs -structured output. JSON and schema mismatches in generated content are -validation results; source access, decoding, registration, and compilation -failures are operational errors. - -## Artifacts - -`internal/artifact` owns the framework's ordinary inline and unrestricted file -reader. The public engine uses it by default and permits consumers to replace it -for every input through the public `ArtifactReader` extension. The -HTTP adapter owns its restricted reader for HTTP containment: `serve` injects -that reader into the public engine with `WithArtifactReader`. - -The rooted reader cleans paths and applies lexical containment without resolving -symlinks. It checks relative references against the configured root and accepts -absolute references only when they remain inside that lexical root. The OS still -follows symlinks after that check. The public containment outcome is documented -by the [HTTP API reference](../api.md); deployment permissions belong in -[operations](../operations.md). - -## Failure Boundaries - -Source packages report repository, decoding, duplicate, validation, and read -failures to their callers. They do not select public status codes or response -schemas. The runner categorizes source failures and the public engine preserves -the corresponding public error identities; adapters map those identities to -their own external contract. - -Source reads use current filesystem or `fs.FS` content for each request. These -packages create no manifests, checkpoints, or durable run state. +Reader errors remain identifiable after Promptkit wraps them as artifact-load +failures, allowing the HTTP adapter to preserve Scriptorium status and error +codes. ## Verification And Change Recipe Inspect: -- `internal/promptdef/repository_test.go` -- `internal/profile/repository_test.go` -- `internal/profile/builtin/repository_test.go` -- `internal/artifact/reader_test.go` +- `internal/config/config_test.go` +- `internal/adapter/cli/run_test.go` - `internal/adapter/http/artifact_reader_test.go` -- `internal/validate/standard_validator_test.go` -- `engine_test.go` +- `internal/adapter/http/handler_test.go` -When updating prompt, profile, schema, or built-in assets: +When changing an application source location or HTTP artifact policy: -1. keep assets valid for the strict loader and the relevant source boundary; -2. update the [configuration reference](../config.md) when a file-format, - catalog, or default changes; -3. run focused source and integration tests, including the built-in repository - test when embedded assets change; and -4. update this document when discovery, precedence, containment, or failure - mechanics change. - -The [testing policy](../policy/testing.md) owns global test sufficiency. +1. preserve strict configuration precedence and the Promptkit public boundary; +2. keep containment and size policy in Scriptorium; +3. update focused configuration, reader, and handler tests; +4. update the [configuration](../config.md), [HTTP](../api.md), and + [operations](../operations.md) contracts as applicable; and +5. do not duplicate Promptkit loaders, formats, or ordinary artifact behavior. diff --git a/docs/operations.md b/docs/operations.md index 06bab09..ecf551b 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -7,8 +7,11 @@ recovery for Scriptorium. It does not redefine invocation syntax, configuration fields, or HTTP wire behavior. - [CLI reference](cli.md): commands, output destinations, and exit codes. -- [Configuration reference](config.md): configuration, prompt/profile/schema - formats, defaults, and credentials. +- [Configuration reference](config.md): application settings, source + locations, defaults, and credential mapping. +- [Promptkit framework formats](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/formats.md): + prompt, profile, schema, execution-setting, and framework credential + contracts. - [HTTP API reference](api.md): route, request/response schema, status codes, limits, and HTTP artifact access. - [Consumer integration overview](consumers/api.md): caller responsibilities. @@ -26,10 +29,10 @@ responsibilities. ## Deploy The Filesystem And Process -Provide the process with readable prompt, profile, and schema sources. Keep -prompt templates adjacent to the prompt definitions that reference them. For an -HTTP deployment that accepts file artifacts, use a dedicated, narrow artifact -directory rather than a general-purpose or sensitive filesystem tree. +Provide the process with readable configured Promptkit prompt, profile, and +schema sources that follow the tagged framework formats. For an HTTP deployment +that accepts file artifacts, use a dedicated, narrow artifact directory rather +than a general-purpose or sensitive filesystem tree. Run Scriptorium under an identity that can: diff --git a/docs/policy/architecture.md b/docs/policy/architecture.md index a1bb835..dfa1082 100644 --- a/docs/policy/architecture.md +++ b/docs/policy/architecture.md @@ -1,83 +1,102 @@ # 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. +This document defines Scriptorium's current application architecture and +durable development boundaries. ## System Shape -Scriptorium is a narrow prompt-execution application with three executable -entry paths: CLI `run`, CLI `render`, and the HTTP service started by `serve`. -It also provides a public Go package for in-process use. Executable adapters -consume framework behavior through that public facade; the facade continues to -compose the framework implementation inside this single repository. Its current -component inventory is maintained in the [internal overview](../internal/overview.md). +Scriptorium is an executable application with three entry paths: CLI `run`, CLI +`render`, and the HTTP service started by `serve`. It does not expose a reusable +root Go package. -Domain behavior is centralized in `internal/usecase` and `internal/domain`. +The application consumes +[Promptkit v0.1.0](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/consumers/pkg-promptkit.md) +through its supported root package. Promptkit owns prompt execution, +preparation, source formats, built-in profiles, model-client behavior, and +validation. Scriptorium owns application configuration, executable adapters, +prepared-run presentation, process behavior, and HTTP deployment policy. -## 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 public engine - requests/results and should not hold framework decisions. -- Keep boundaries explicit: repositories/loaders/renderers/validators/LLM client stay behind package interfaces. -- Keep external decoding strict: configuration, prompt, and profile YAML and - HTTP JSON should reject unknown fields. -- Keep secrets out of payloads: raw API key values must not be accepted or emitted. +The concrete package inventory is maintained in the +[internal overview](../internal/overview.md). ## Dependency Direction -- Adapters translate external shapes and IO concerns; they do not make - use-case decisions. -- Executable adapters and prepared-run formatting use the public facade for - framework behavior rather than importing framework implementation packages - directly. -- Use-case and domain code depend on explicit repository, renderer, validator, - and LLM interfaces rather than adapter implementations. -- Source, rendering, validation, and LLM implementations remain behind their - package boundaries. -- Dependency-specific types must not leak across unrelated package boundaries. -- Prefer the standard library; add an external dependency only when it - materially reduces risk or complexity. +```text +cmd/scriptorium + | + v +CLI and HTTP adapters, configuration, defaults, and formatting + | + v +gitea.maximumdirect.net/eric/promptkit +``` -## State And Persistence Policy +- Retained application packages may import Promptkit's root package. +- They must not import Promptkit `internal` packages. +- They must not import the removed Scriptorium root facade or recreate former + framework package families. +- Adapter-owned interfaces use Promptkit public values when a consumer-side + substitution boundary is needed. +- Scriptorium passes omitted framework settings as zero values so Promptkit + applies its own defaults. -Scriptorium has no durable run-state store. +The repository architecture guard enforces these import and removal +invariants. -- No built-in resume/checkpoint/archive behavior. -- Recovery model is rerun after correcting inputs/config/environment. +## Retained Boundaries -## Contract Ownership +- `internal/adapter/cli` owns commands, flags, configuration precedence, + process streams, output files, summaries, and exit codes. +- `internal/adapter/http` owns routes, strict JSON DTOs, size limits, response + mapping, status mapping, and the restricted artifact reader. +- `internal/config` owns discovery and strict decoding of Scriptorium + application configuration. +- `internal/defaults` owns Scriptorium application and HTTP defaults only. +- `internal/format` owns deterministic prepared-run text and JSON presentation. +- Promptkit owns framework orchestration and contracts. Its + [format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/formats.md) + and + [outbound integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/integrations/openai-compatible-chat.md) + are canonical. -The [CLI](../cli.md), [configuration](../config.md), [HTTP API](../api.md), -[public Go package](../consumers/pkg-scriptorium.md), and -[integration](../integrations/) documents own their respective external -contracts. This policy keeps only the architectural boundaries that govern -their implementation. +## HTTP Artifact Security Boundary -## Error Handling And Logging +Ordinary CLI file loading is provided by Promptkit. Scriptorium's HTTP adapter +injects a restricted `promptkit.ArtifactReader` for inbound HTTP requests. +That reader denies file references without an artifact root, enforces the +configured byte limit, and applies Scriptorium's lexical root-containment rule. +The operating system still follows symlinks after the lexical check. -- Wrap errors with domain/operation context. -- Map public error identities to adapter-appropriate statuses/codes without - leaking sensitive internals. -- Never emit raw secret values. +The [HTTP API](../api.md) owns observable request outcomes, and +[operations](../operations.md) owns deployment permissions and root selection. -## Testing And Documentation +## State, Errors, And Secrets -Testing philosophy and change-validation expectations are defined by the -[testing policy](testing.md). Documentation ownership and maintenance rules are -defined by the [documentation policy](documentation.md). +Scriptorium has no durable run-state store, checkpoint, cache, or resume +mechanism. Recovery is a new request after correcting inputs, configuration, or +environment. + +Adapters map Promptkit public error identities into 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. ## Architectural Invariants -- `Runner.Run` reuses `Runner.Prepare` flow. -- Raw API key values must not be accepted through external configuration or - request payloads, and resolved secret values must not be emitted. +- External YAML and JSON decoding remains strict. +- CLI and HTTP behavior remains presentation and transport logic rather than + framework orchestration. +- Explicit numeric request overrides preserve presence, including zero. +- HTTP artifact containment and byte limits remain Scriptorium policy. +- No application package depends on Promptkit implementation packages. ## 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. +- 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. Work that is not implemented belongs in `docs/roadmap/`. diff --git a/docs/policy/documentation.md b/docs/policy/documentation.md index ac22942..44361c6 100644 --- a/docs/policy/documentation.md +++ b/docs/policy/documentation.md @@ -69,11 +69,11 @@ secret values. | Documentation organization | `docs/policy/documentation.md` | Documentation ownership, audience boundaries, maintenance rules, and ADR/document lifecycle. | Application architecture or product behavior. | | Testing policy | `docs/policy/testing.md` | Test philosophy, risk-based sufficiency, test boundaries, doubles, coverage guidance, regression-test policy, and criteria for adding, rewriting, or deleting tests. | Subsystem behavior, application contracts, subsystem-specific test inventories, and implementation plans. | | CLI contract | `docs/cli.md` | Commands, arguments, flags, invocation semantics, and exit codes. | End-to-end operating procedures, configuration field definitions, runtime filesystem layout, module implementation details. | -| Configuration contract | `docs/config.md` | Discovery and precedence, file schema, fields, defaults, environment overrides, validation rules, and user-selectable module or validator keys. | Complete example files, CLI syntax, runtime state lifecycle, module implementation details. | +| Configuration contract | `docs/config.md` | Application discovery and precedence, source locations, server fields, render default, HTTP limits, and credential mapping. | Promptkit framework formats and defaults, complete example files, CLI syntax, runtime lifecycle, and implementation detail. | | Operations | `docs/operations.md` | Runtime workflows, physical filesystem and state layout, output, cache, and debug handling, resume, cleanup, permissions, recovery, and operational limits. | CLI flag syntax, configuration field definitions, logical output schemas, implementation mechanics. | | Public HTTP contract | `docs/api.md` | Routes, authentication, media types, request and response schemas, status codes, pagination, caching, idempotency, rate limits, and HTTP retry semantics. | Client walkthroughs, upstream or downstream integration internals, implementation detail. | -| Consumer guidance | `docs/consumers/` | Task-oriented use of the public interface, minimal client examples, and consumer responsibilities. | HTTP wire semantics, external protocol contracts, internal implementation detail. | -| External and durable integration contracts | `docs/integrations/` | External file formats and protocols, upstream and downstream contracts, logical output bundle paths and schemas, media types, and compatibility behavior. | Physical runtime placement and lifecycle, internal transformations, CLI syntax, configuration defaults. | +| Consumer guidance | `docs/consumers/` | Choosing between Scriptorium's executable interfaces and understanding consumer responsibilities. | HTTP wire semantics, CLI syntax, Promptkit's Go package, and internal implementation detail. | +| External and durable integration contracts | `docs/integrations/` | Scriptorium-owned process and executable integration contracts. | Promptkit framework formats and outbound provider protocols, physical runtime placement, internal transformations, CLI syntax, and configuration defaults. | | Implemented component inventory | `docs/internal/overview.md` | Current packages and components, their implemented responsibilities, and links to focused internal docs. | Normative architecture, contributor reading policy, external contracts. | | Internal component behavior | Other files under `docs/internal/` | Implementation flow, internal collaborators and state transitions, package-local guarantees and failures, and relevant tests. | Global architecture invariants, configuration definitions and defaults, external schemas, operator procedures. | | Architectural decision history | `docs/adr/` | Significant decisions, context, alternatives, rationale, consequences, and supersession history. | Current behavior reference, implementation status, task sequencing. | diff --git a/docs/policy/testing.md b/docs/policy/testing.md index 2c33178..a30e803 100644 --- a/docs/policy/testing.md +++ b/docs/policy/testing.md @@ -77,7 +77,7 @@ Test through the narrowest stable boundary that expresses the behavior clearly. This is often the package API, but it may instead be: -- a smaller pure function when dense domain logic is most clearly isolated there; +- a smaller pure function when dense application logic is most clearly isolated there; - a package-level operation when several internal collaborators jointly produce the behavior; or - a larger integration boundary when correctness emerges from interaction with a real dependency. @@ -162,13 +162,16 @@ Use a test-controlled limit and measure the behavior relative to that limit. Do Each behavior should have a clear test owner. -- Parser tests own parsing cases. -- Validator tests own validation rules. -- Domain tests own transformations and invariants. -- Adapter tests own external integration behavior. -- Orchestrator tests own coordination and failure propagation. -- CLI tests own argument and configuration mapping. -- End-to-end tests prove that representative assembled workflows work. +- Configuration tests own application YAML, discovery, precedence, and + application defaults. +- CLI tests own argument mapping, streams, summaries, exit behavior, and + representative command workflows. +- HTTP tests own DTOs, strict decoding, limits, status mapping, and restricted + artifact policy. +- Formatter tests own prepared-run text and JSON presentation. +- Architecture tests own dependency direction and removal invariants. +- Promptkit owns framework parsing, orchestration, validation, profiles, and + model-client behavior. Higher-level tests should not repeat every lower-level case. A single intentional policy change should not require unrelated edits across many test files. @@ -221,7 +224,9 @@ Coverage is a diagnostic, not a target. Use it to find untested critical branches and unexpectedly weak packages. Do not write low-value tests solely to increase a percentage, and do not infer test quality from coverage alone. -Pure domain logic will often warrant higher coverage than CLI wiring or external adapters. Uneven coverage is acceptable when it reflects risk. +Security-sensitive HTTP containment and external mappings may warrant denser +coverage than straightforward process wiring. Uneven coverage is acceptable +when it reflects risk. Increasing coverage is valuable only when the newly covered behavior protects a meaningful risk at an acceptable cost. diff --git a/docs/roadmap/migration.md b/docs/roadmap/migration.md index 808b46e..815be10 100644 --- a/docs/roadmap/migration.md +++ b/docs/roadmap/migration.md @@ -231,9 +231,9 @@ passes its documented validation, and has published its first versioned tag before Scriptorium or another consumer adopts it, as required by [ADR 0003](../adr/0003-use-maintainer-run-validation-and-tag-only-releases-for-promptkit.md). -**Gate status:** Complete as of 2026-07-28. The -[Step 6 completion record](step6.md) records source Scriptorium commit -`c7263ab2a8e58f7fb97280082d327a820c7cece7`, accepted Promptkit commit +**Gate status:** Complete as of 2026-07-28. Repository history records source +Scriptorium commit `c7263ab2a8e58f7fb97280082d327a820c7cece7`, +accepted Promptkit commit `9e68a2bbf779545995270c47842048a3bc6c85dc`, independently passing acceptance, published annotated tag `v0.1.0`, and successful remote-consumer validation. Scriptorium remains unchanged at its pre-cutover boundary. Step 7 adoption of