Document Scriptorium as a Promptkit application

This commit is contained in:
2026-07-28 14:21:19 +00:00
parent fb0b21c51d
commit 7bb4cf35b9
18 changed files with 327 additions and 1031 deletions

View File

@@ -1,12 +1,15 @@
# scriptorium # Scriptorium
Scriptorium is a narrow prompt-execution application for rendering prompt Scriptorium is a prompt-execution application with a command-line interface and
requests, running them against OpenAI-compatible chat-completions endpoints, and an HTTP service. It prepares prompt requests, runs them against
serving the same run workflow over HTTP. OpenAI-compatible model endpoints, and returns generated output with validation
metadata.
It keeps prompt definitions, execution profiles, schemas, and input artifacts as The application uses
separate files so prompts can be reviewed and reused without baking model [Promptkit v0.1.0](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/)
runtime settings into application code. 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 ## Quickstart
@@ -21,8 +24,9 @@ go run ./cmd/scriptorium render \
--format json --format json
``` ```
This command renders the prepared prompt and effective runtime settings without calling an LLM. This renders the prepared prompt and effective runtime settings without calling
For complete invocation and output behavior, see the [CLI reference](docs/cli.md). a model. For complete invocation and output behavior, see the
[CLI reference](docs/cli.md).
## Documentation ## Documentation
@@ -31,15 +35,16 @@ For complete invocation and output behavior, see the [CLI reference](docs/cli.md
- [HTTP API reference](docs/api.md) - [HTTP API reference](docs/api.md)
- [Operations guide](docs/operations.md) - [Operations guide](docs/operations.md)
- [Consumer integration overview](docs/consumers/api.md) - [Consumer integration overview](docs/consumers/api.md)
- [Go library package](docs/consumers/pkg-scriptorium.md)
- [Subprocess integration](docs/integrations/subprocess.md) - [Subprocess integration](docs/integrations/subprocess.md)
- [OpenAI-compatible chat integration](docs/integrations/openai-compatible-chat.md)
- [Architecture policy](docs/policy/architecture.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 ## Examples
- [Minimal configuration](examples/config.yml) and [complete configuration](examples/config.full.yml) - [Minimal configuration](examples/config.yml) and
- [Prompt definitions](examples/prompts/), [execution profiles](examples/profiles/), [schemas](examples/schemas/), and [synthetic input fixtures](examples/fixtures/) [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) - [Render script](examples/render-markdown-summary.sh)
- [HTTP request](examples/http-run.json) - [HTTP request](examples/http-run.json)
- [Go library example](examples/go-library/prepare/main.go)

View File

@@ -66,11 +66,12 @@ untrusted writers.
The optional `model` object accepts `endpoint`, `model`, `temperature`, The optional `model` object accepts `endpoint`, `model`, `temperature`,
`max_tokens`, `top_p`, `timeout_seconds`, `service_tier`, `max_tokens`, `top_p`, `timeout_seconds`, `service_tier`,
`reasoning_effort`, `api_key_env`, and `extra_params`. Numeric ranges and `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 Explicit zero values for the numeric fields are overrides; zero
`timeout_seconds` disables the per-generation deadline only, retaining the `timeout_seconds` disables the per-generation deadline only, retaining the
request context and configured transport cap. The timeout layers are defined in 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 Raw API-key values are not accepted. `api_key` and any other unknown model
field cause `400 invalid_json`. field cause `400 invalid_json`.

View File

@@ -1,7 +1,7 @@
# CLI Reference # CLI Reference
This is the canonical contract for invoking Scriptorium. Configuration discovery, 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 [configuration reference](config.md). The [HTTP API reference](api.md) owns
service request and response behavior. 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 durations are converted to whole seconds by truncation toward zero, so any
duration whose absolute value is below one second becomes an explicit duration whose absolute value is below one second becomes an explicit
zero-second override. The timeout layers are defined in the 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`. There is no raw API-key flag. Use `--api-key-env`.

View File

@@ -1,15 +1,17 @@
# Configuration Reference # Configuration Reference
This is the canonical reference for Scriptorium application settings and the This is the canonical reference for Scriptorium application settings. Prompt,
prompt, profile, and schema files those settings select. For command syntax, profile, schema, execution-setting, built-in profile, and framework credential
see the [CLI reference](cli.md); for HTTP request shapes, limits, and outcomes, semantics are defined by the
see the [HTTP API reference](api.md). [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 ## Discovery And Precedence
Application settings are resolved in this order: Application settings are resolved in this order:
1. built-in defaults; 1. built-in Scriptorium defaults;
2. a configuration file; then 2. a configuration file; then
3. CLI overrides. 3. CLI overrides.
@@ -19,7 +21,7 @@ If neither exists, it uses built-in defaults. An explicit `--config` path must
exist and decode successfully. exist and decode successfully.
The maintained [minimal configuration](../examples/config.yml) and 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 ## Application Configuration File
@@ -28,146 +30,57 @@ do not override a prior value. Raw API-key fields are not accepted.
| Field | Default | Meaning | | Field | Default | Meaning |
| --- | --- | --- | | --- | --- | --- |
| `prompt_dir` | unset | Directory containing prompt-definition YAML. `run`, `render`, and `serve` require an effective value. | | `prompt_dir` | unset | Promptkit prompt-definition source directory. `run`, `render`, and `serve` require an effective value. |
| `profile_dir` | unset | Directory containing custom profile YAML. Built-in profiles remain available. | | `profile_dir` | unset | Optional custom Promptkit profile source directory overlaid on Promptkit built-ins. |
| `schema_dir` | `.` | Base directory for relative JSON Schema paths. | | `schema_dir` | `.` | Promptkit schema source directory for relative schema paths. |
| `server.addr` | `:8080` | Address used by `serve`. | | `server.addr` | `:8080` | Address used by `serve`. |
| `server.artifact_root` | unset | Root that enables HTTP `file` input references. | | `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_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. | | `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 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 the each limit is enforced and reported. `server.artifact_root` configures an HTTP
deployment boundary; see the [HTTP API reference](api.md) for request-path and deployment boundary; see [operations](operations.md) for deployment handling.
containment behavior, and [operations](operations.md) for deployment handling.
## Prompt Definition Files ## Framework Source Mapping
Prompt definitions are strict YAML files anywhere below `prompt_dir`. A prompt Scriptorium passes `prompt_dir`, `profile_dir`, and `schema_dir` to Promptkit
is selected by its YAML `id`, not by file path; nested directories are only for when constructing its engine. Scriptorium does not redefine or independently
organization. See [maintained prompt examples](../examples/prompts/). parse those framework file formats.
| Field | Required | Meaning | - Prompt selection, versions, message templates, inputs, output contracts, and
| --- | --- | --- | session IDs are Promptkit contracts.
| `id` | yes | Prompt identifier. | - Profile fields, numeric ranges, execution defaults, overlay precedence,
| `version` | yes | Prompt version. | built-in profiles, and credential rules are Promptkit contracts.
| `default_profile` | no | Profile used when a request omits a profile ID. | - Schema path behavior and generated-content validation are Promptkit
| `description` | no | Human-readable description. | contracts.
| `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. |
### 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`, ## Credentials And Outbound Behavior
`content_type`, and `description` fields. Input names must be unique.
Each message has a required `role`, exactly one of `content` or `content_file`, Scriptorium maps `--api-key-env` and HTTP `model.api_key_env` into Promptkit
and optional `cache_control`. A `content_file` path is relative to the prompt request overrides. Keep secret values in environment variables and store only
file. `cache_control.type` must be `ephemeral`; its optional `ttl` is `1h`. 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 Promptkit's
values are omitted. A rendered value may contain at most 256 Unicode code [OpenAI-compatible integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/integrations/openai-compatible-chat.md)
points. defines outbound authentication, provider request mapping, transport limits,
and timeout layering.
### 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.
## Related References ## Related References
- [CLI reference](cli.md) - [CLI reference](cli.md)
- [HTTP API reference](api.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)

View File

@@ -1,45 +1,21 @@
# Consumer Integration Overview # Consumer Integration Overview
This guide helps applications choose a Scriptorium interface and understand Scriptorium exposes executable interfaces. Choose between a local subprocess
their responsibilities. The linked contracts own interface syntax and wire and the HTTP service according to the boundary your application needs.
semantics.
| Interface | Use when | | Interface | Use when |
| --- | --- | | --- | --- |
| Go package | The consumer is Go and needs typed requests, results, or an injected LLM client. | | CLI subprocess | The consumer needs a synchronous local process boundary or prepared output. |
| CLI subprocess | The consumer needs process isolation or is not written in Go. |
| HTTP API | The consumer needs a service boundary or remote access. | | 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) - CLI subprocess: [subprocess integration](../integrations/subprocess.md)
- HTTP service: [HTTP API reference](../api.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 applications that need an in-process prompt framework should import
Promptkit directly. The tagged
```go [Promptkit Go consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/consumers/pkg-promptkit.md)
engine, err := scriptorium.NewEngine(scriptorium.Config{ owns that interface; Scriptorium does not provide a Go library package.
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).
## Consumer Responsibilities ## Consumer Responsibilities
@@ -47,13 +23,14 @@ Consumers are responsible for:
- selecting and deploying prompt, profile, and schema assets; - selecting and deploying prompt, profile, and schema assets;
- supplying required inputs and template variables; - supplying required inputs and template variables;
- supplying credentials through the applicable interface; - supplying credentials through the chosen interface;
- protecting rendered prompts and generated artifacts as potentially sensitive; - protecting rendered prompts and generated artifacts as potentially
sensitive;
- deciding whether validation-failed output is usable; and - deciding whether validation-failed output is usable; and
- retrying only when another model call is acceptable. - retrying only when another model call is acceptable.
Scriptorium does not persist run state. A retry can produce different output and Scriptorium does not persist run state. A retry can produce different output
can incur another provider request. CLI exit behavior belongs to the and can incur another provider request. CLI exits belong to the
[CLI reference](../cli.md); HTTP status 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 [HTTP API reference](../api.md), and framework semantics belong to
[package contract](pkg-scriptorium.md). [Promptkit v0.1.0](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/formats.md).

View File

@@ -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).

View File

@@ -1,63 +1,56 @@
# Development # Development
This is the contributor entry point for Scriptorium. Use the task-specific This is the contributor entry point for Scriptorium. Scriptorium is an
reading guide below before making changes. Canonical architecture, contracts, application that consumes the public
component behavior, and policies remain in their owning documents. [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 ## Initial Orientation
Before starting work: Before starting work:
1. inspect the working tree and preserve unrelated changes; 1. inspect the working tree and preserve unrelated changes;
2. read the architecture policy for code or design work; 2. read the [architecture policy](policy/architecture.md);
3. read the policy, contract, and internal documents listed for the task; 3. follow the task-specific contracts and internal documents below; and
4. inspect the relevant implementation and tests before deciding how to change 4. inspect the relevant implementation and tests before changing them.
them.
Start with: Also read the [documentation policy](policy/documentation.md) before changing
documentation and the [testing policy](policy/testing.md) before changing
- [Architecture policy](policy/architecture.md) for system boundaries, tests.
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.
## Task-Specific Reading Guide ## Task-Specific Reading Guide
| Task | Read before changing | | Task | Read before changing |
| --- | --- | | --- | --- |
| Repository orientation or component responsibility | [Internal component overview](internal/overview.md) and [architecture policy](policy/architecture.md) | | 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) and [adapter internals](internal/adapters.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, status mapping, or artifact policy | [HTTP API contract](api.md), [adapter internals](internal/adapters.md), and [source internals](internal/sources.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 or precedence | [Configuration contract](config.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) | | Prepared-run presentation | [CLI contract](cli.md), [adapter internals](internal/adapters.md), and `internal/format` |
| Prompt, profile, schema, or artifact loading | [Configuration contract](config.md), [internal component overview](internal/overview.md), and [source internals](internal/sources.md) | | 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) |
| Runner orchestration, rendering, validation, or repair | [Runner internals](internal/runner.md) and [source internals](internal/sources.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) |
| 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) |
| Subprocess behavior | [Subprocess integration](integrations/subprocess.md) and [CLI contract](cli.md) | | Subprocess behavior | [Subprocess integration](integrations/subprocess.md) and [CLI contract](cli.md) |
| Runtime operation or recovery | [Operations](operations.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/` | | Release packaging | `.woodpecker/release.yml`, [operations](operations.md), and the architecture policy |
| 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/` | | 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 Cross-project changes land and release in Promptkit before Scriptorium adopts
documents own detailed subsystem change recipes. the tagged version. Do not commit a Go workspace, local replacement, vendored
Promptkit source, or an import of a Promptkit `internal` package.
## Baseline Validation ## Baseline Validation
Use focused checks while iterating, then run validation proportionate to the For code changes, run:
change and the risks described by the testing policy.
The repository-level baseline for code changes is:
```bash ```bash
go test ./... go test ./...
go test -race ./...
go vet ./... go vet ./...
go build ./cmd/scriptorium go build ./cmd/scriptorium
``` ```
Documentation-only work does not require the full Go suite unless it changes Check formatting with `gofmt`, run `git diff --check`, and validate affected
commands, examples, generated output, or another behavior that the suite examples and documentation links. Documentation-only work does not require
validates. Always check changed links, paths, examples, and canonical ownership. unrelated new tests, but commands and examples changed by documentation must be
run.

View File

@@ -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 <key>` 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).

View File

@@ -2,115 +2,86 @@
## Purpose ## Purpose
Adapters translate external inputs into public engine requests and translate Scriptorium adapters translate executable inputs into Promptkit public requests
public results or errors back to their interface. They own IO and presentation and translate Promptkit results or errors back to CLI or HTTP behavior. They
mechanics; use-case decisions remain behind the root `scriptorium` facade. own IO and presentation mechanics, not framework decisions.
External contracts are canonical in the [CLI reference](../cli.md), [HTTP API External contracts are canonical in the [CLI reference](../cli.md) and
reference](../api.md), and [Go package contract](../consumers/pkg-scriptorium.md). [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 ## Components And Collaborators
- `cmd/scriptorium` passes process arguments and streams to - `cmd/scriptorium` passes process arguments and streams to
`internal/adapter/cli`. `internal/adapter/cli`.
- `internal/adapter/cli` parses commands, resolves application settings through - `internal/adapter/cli` resolves settings through `internal/config`,
`internal/config`, constructs the public engine, and owns process output constructs `promptkit.Engine`, maps CLI values to `promptkit.RunRequest`,
handling. and owns output files, summaries, and exit codes.
- `internal/adapter/http` decodes DTOs, maps them to public run requests, - `internal/adapter/http` strictly decodes request DTOs, maps them to Promptkit
calls its local public `Runner` interface, and maps public errors and results public values, calls its adapter-owned `Runner` interface, and maps results
to HTTP DTOs. and errors to HTTP DTOs.
- The root `scriptorium` package maps its public types and options to internal - `internal/format` renders `promptkit.PreparedRun` values as deterministic text
collaborators and maps selected internal errors to public sentinels. or JSON.
- `internal/format` formats public prepared runs for the CLI.
## Wiring Flows ## Wiring Flows
### CLI ### CLI
The CLI resolves configuration before constructing the public engine. `run` `run` calls `promptkit.Engine.Run`; `render` calls
calls `Engine.Run` with a public request and `render` calls `Engine.Prepare` `promptkit.Engine.Prepare`. Both share request mapping for prompt/profile
with the same request mapping. `serve` constructs the HTTP-owned restricted selection, file inputs, variables, and presence-aware execution overrides.
artifact reader, injects it with `WithArtifactReader`, passes the resulting Omitted framework settings remain zero values so Promptkit resolves its own
engine directly to the HTTP handler, and starts the server. defaults.
Parser state records whether numeric runtime values were explicitly supplied. `serve` constructs Scriptorium's restricted HTTP artifact reader, injects it
That presence is carried into `scriptorium.ExecutionTargetOverride`, allowing with `promptkit.WithArtifactReader`, passes the engine through the HTTP
the engine to distinguish omitted values from explicit zero overrides. adapter's consumer-owned `Runner` interface, and starts the server.
### HTTP ### HTTP
The handler first enforces transport limits, strict JSON decoding, and the The handler enforces transport limits and strict JSON decoding before mapping
minimal request shape. It maps DTO values to public types without deciding DTOs into `promptkit.RunRequest`, `promptkit.ArtifactRef`, and
prompt selection, source behavior, or validation semantics. On success it maps `promptkit.ExecutionTargetOverride`. On success it reads Promptkit artifact,
the public result to the response DTO; on failure it uses `errors.Is` over validation, model, usage, and metadata values directly.
public framework errors and HTTP-local artifact-policy errors to choose the
public error mapping.
The [HTTP API reference](../api.md) owns the route, DTO schema, status codes, Failure mapping uses `errors.Is` against Promptkit's public sentinels and the
and externally observable limit behavior. HTTP reader's Scriptorium-owned containment and size errors. Wrapped reader
errors preserve their identity through Promptkit's artifact-load boundary.
### 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.
## Package-Local Guarantees ## Package-Local Guarantees
- Adapters do not embed framework orchestration or source-loading decisions. - Adapters contain no copied framework types or orchestration.
- Configuration is resolved before adapter dependency composition. - Configuration is resolved before Promptkit engine construction.
- CLI and HTTP consume the public engine without a repairer; a repairer remains - Explicit numeric overrides preserve presence, including zero.
available only through explicit internal runner construction. - HTTP DTO and error mapping remains stable and transport-owned.
- DTO conversion preserves explicit numeric-override presence. - Resolved secrets are not serialized or printed.
- Error mapping matches error identities, not error text. - No adapter creates durable run state.
- No adapter creates durable run state; caller-selected output files are not
application state.
## Failure And Verification Boundaries ## Verification
Keep external error payloads concise, preserve strict external decoding, and do Inspect:
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:
- `internal/adapter/cli/run_test.go` - `internal/adapter/cli/run_test.go`
- `internal/adapter/http/handler_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/format/prepared_run_test.go`
- `internal/adapter/dependency_test.go`
Run the affected adapter package tests and recheck the relevant canonical The adapter tests protect parsing, configuration mapping, output, status
contract. The [testing policy](../policy/testing.md) owns global test mapping, restricted artifacts, and representative real Promptkit-engine
sufficiency guidance. workflows. The dependency test protects the repository boundary.
## Change Recipes ## Change Recipes
### Application Configuration Fields For a CLI or HTTP change:
1. Add the field to the relevant `internal/config` shape and default handling. 1. identify the Scriptorium-owned external contract;
2. Parse and validate it, then preserve configuration and CLI-override 2. map through Promptkit public values without copying framework semantics;
precedence while wiring it through its consuming adapter. 3. add or update the narrow application-owned test;
3. Add focused configuration and adapter tests for parsing, mapping, and 4. update the canonical Scriptorium contract; and
effective behavior. 5. coordinate and tag Promptkit first if a required public capability is
4. Update the [configuration contract](../config.md) and any affected external genuinely absent.
contract.
### CLI Flags Update [source internals](sources.md) when application source locations or HTTP
artifact containment changes.
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.

View File

@@ -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.

View File

@@ -1,48 +1,18 @@
# Internal Component Overview # Internal Component Overview
## Purpose This is the complete inventory of Scriptorium's implemented Go components.
The [architecture policy](../policy/architecture.md) owns normative boundaries;
This is the inventory of Scriptorium's implemented components for contributors. public behavior belongs in the linked contracts.
The [architecture policy](../policy/architecture.md) owns normative boundaries
and invariants; public behavior belongs in the linked contracts.
## Public And Command Entrypoints
| Component | Implemented responsibility | References | | 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 arguments and streams to the CLI adapter. | [CLI contract](../cli.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) | | `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 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)
| Component | Implemented responsibility | References | and are not part of this repository.
| --- | --- | --- |
| `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.

View File

@@ -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.

View File

@@ -2,98 +2,67 @@
## Purpose ## Purpose
This document describes how source packages load prompt definitions, profiles, This document covers Scriptorium-owned source locations and the restricted HTTP
schemas, and artifacts. The [configuration reference](../config.md) owns their artifact reader. Prompt, profile, schema, and ordinary artifact semantics are
user-facing formats and settings. The [HTTP API reference](../api.md) owns owned by the tagged
HTTP-visible artifact outcomes; [operations](../operations.md) owns deployment [Promptkit format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/docs/formats.md).
handling.
## Prompt Definitions ## Application Source Locations
`internal/promptdef` provides filesystem and `fs.FS` repositories. Both use `internal/config` resolves `prompt_dir`, `profile_dir`, and `schema_dir` from
`internal/filecatalog` for recursive YAML discovery, deterministic ordering, Scriptorium defaults, configuration files, and CLI overrides.
display paths, and root cleaning. `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 Scriptorium does not search, parse, validate, or overlay framework source files
path. They decode through strict YAML handling, reject duplicate matching itself. Promptkit owns prompt selection, profile built-ins and overlays, schema
definitions, and resolve `content_file` relative to the definition. The `fs.FS` resolution, ordinary file artifacts, and the related error identities.
implementation resolves content paths inside its source root; absolute paths and
traversal outside that root are rejected before file access.
## 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. ## Restricted HTTP Artifact Reader
`internal/profile/builtin` exposes embedded assets through the same repository
interface.
An overlay asks its primary source first. It falls back only when the primary `internal/adapter/http` implements `promptkit.ArtifactReader` for HTTP
reports `ErrProfileNotFound`; invalid YAML, duplicate IDs, validation failures, requests. The `serve` path injects it with
and raw-key failures are returned rather than hidden by fallback. This makes a `promptkit.WithArtifactReader`, replacing Promptkit's ordinary reader for
custom ID override a built-in ID while retaining errors in the custom source. inbound HTTP inputs.
The public engine can overlay in-memory profiles ahead of both file-backed and The reader:
built-in repositories. Profile field definitions, validation ranges, and the
built-in catalog remain in the [configuration reference](../config.md).
## 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 Containment is lexical and does not resolve symlinks. The operating system
`FSValidator` for `fs.FS` sources. Directory-backed validation loads the named follows symlinks after the check. The [HTTP API](../api.md) owns observable
schema path; it does not search directories by basename. `fs.FS` schema paths request outcomes, and [operations](../operations.md) owns safe deployment
are cleaned and checked against their configured root, while a single-file permissions and root selection.
source matches its file base name.
The runner requests a schema document before generation when it needs Reader errors remain identifiable after Promptkit wraps them as artifact-load
structured output. JSON and schema mismatches in generated content are failures, allowing the HTTP adapter to preserve Scriptorium status and error
validation results; source access, decoding, registration, and compilation codes.
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.
## Verification And Change Recipe ## Verification And Change Recipe
Inspect: Inspect:
- `internal/promptdef/repository_test.go` - `internal/config/config_test.go`
- `internal/profile/repository_test.go` - `internal/adapter/cli/run_test.go`
- `internal/profile/builtin/repository_test.go`
- `internal/artifact/reader_test.go`
- `internal/adapter/http/artifact_reader_test.go` - `internal/adapter/http/artifact_reader_test.go`
- `internal/validate/standard_validator_test.go` - `internal/adapter/http/handler_test.go`
- `engine_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; 1. preserve strict configuration precedence and the Promptkit public boundary;
2. update the [configuration reference](../config.md) when a file-format, 2. keep containment and size policy in Scriptorium;
catalog, or default changes; 3. update focused configuration, reader, and handler tests;
3. run focused source and integration tests, including the built-in repository 4. update the [configuration](../config.md), [HTTP](../api.md), and
test when embedded assets change; and [operations](../operations.md) contracts as applicable; and
4. update this document when discovery, precedence, containment, or failure 5. do not duplicate Promptkit loaders, formats, or ordinary artifact behavior.
mechanics change.
The [testing policy](../policy/testing.md) owns global test sufficiency.

View File

@@ -7,8 +7,11 @@ recovery for Scriptorium. It does not redefine invocation syntax, configuration
fields, or HTTP wire behavior. fields, or HTTP wire behavior.
- [CLI reference](cli.md): commands, output destinations, and exit codes. - [CLI reference](cli.md): commands, output destinations, and exit codes.
- [Configuration reference](config.md): configuration, prompt/profile/schema - [Configuration reference](config.md): application settings, source
formats, defaults, and credentials. 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, - [HTTP API reference](api.md): route, request/response schema, status codes,
limits, and HTTP artifact access. limits, and HTTP artifact access.
- [Consumer integration overview](consumers/api.md): caller responsibilities. - [Consumer integration overview](consumers/api.md): caller responsibilities.
@@ -26,10 +29,10 @@ responsibilities.
## Deploy The Filesystem And Process ## Deploy The Filesystem And Process
Provide the process with readable prompt, profile, and schema sources. Keep Provide the process with readable configured Promptkit prompt, profile, and
prompt templates adjacent to the prompt definitions that reference them. For an schema sources that follow the tagged framework formats. For an HTTP deployment
HTTP deployment that accepts file artifacts, use a dedicated, narrow artifact that accepts file artifacts, use a dedicated, narrow artifact directory rather
directory rather than a general-purpose or sensitive filesystem tree. than a general-purpose or sensitive filesystem tree.
Run Scriptorium under an identity that can: Run Scriptorium under an identity that can:

View File

@@ -1,83 +1,102 @@
# Architecture # Architecture
This document is the development architecture policy for Scriptorium. This document defines Scriptorium's current application architecture and
durable development boundaries.
It is for developers and LLM coding agents. User-facing behavior belongs in `README.md` and the docs under `docs/` that target operators/users.
## System Shape ## System Shape
Scriptorium is a narrow prompt-execution application with three executable Scriptorium is an executable application with three entry paths: CLI `run`, CLI
entry paths: CLI `run`, CLI `render`, and the HTTP service started by `serve`. `render`, and the HTTP service started by `serve`. It does not expose a reusable
It also provides a public Go package for in-process use. Executable adapters root Go package.
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).
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 The concrete package inventory is maintained in the
[internal overview](../internal/overview.md).
- 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.
## Dependency Direction ## Dependency Direction
- Adapters translate external shapes and IO concerns; they do not make ```text
use-case decisions. cmd/scriptorium
- Executable adapters and prepared-run formatting use the public facade for |
framework behavior rather than importing framework implementation packages v
directly. CLI and HTTP adapters, configuration, defaults, and formatting
- Use-case and domain code depend on explicit repository, renderer, validator, |
and LLM interfaces rather than adapter implementations. v
- Source, rendering, validation, and LLM implementations remain behind their gitea.maximumdirect.net/eric/promptkit
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.
## 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. ## Retained Boundaries
- Recovery model is rerun after correcting inputs/config/environment.
## 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), ## HTTP Artifact Security Boundary
[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.
## 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. The [HTTP API](../api.md) owns observable request outcomes, and
- Map public error identities to adapter-appropriate statuses/codes without [operations](../operations.md) owns deployment permissions and root selection.
leaking sensitive internals.
- Never emit raw secret values.
## Testing And Documentation ## State, Errors, And Secrets
Testing philosophy and change-validation expectations are defined by the Scriptorium has no durable run-state store, checkpoint, cache, or resume
[testing policy](testing.md). Documentation ownership and maintenance rules are mechanism. Recovery is a new request after correcting inputs, configuration, or
defined by the [documentation policy](documentation.md). 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 ## Architectural Invariants
- `Runner.Run` reuses `Runner.Prepare` flow. - External YAML and JSON decoding remains strict.
- Raw API key values must not be accepted through external configuration or - CLI and HTTP behavior remains presentation and transport logic rather than
request payloads, and resolved secret values must not be emitted. 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 ## Non-Goals
- Do not move orchestration responsibilities from external callers into Scriptorium. - Do not recreate an in-process Scriptorium framework API or compatibility
- Do not add adapter-specific business logic in `internal/adapter/*` packages. facade.
- Do not bypass repository/renderer/validator/LLM boundaries by introducing cross-package coupling. - 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/`. Work that is not implemented belongs in `docs/roadmap/`.

View File

@@ -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. | | 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. | | 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. | | 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. | | 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. | | 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. | | 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/` | 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. | | 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. | | 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. | | 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. | | Architectural decision history | `docs/adr/` | Significant decisions, context, alternatives, rationale, consequences, and supersession history. | Current behavior reference, implementation status, task sequencing. |

View File

@@ -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: 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 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. - 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. Each behavior should have a clear test owner.
- Parser tests own parsing cases. - Configuration tests own application YAML, discovery, precedence, and
- Validator tests own validation rules. application defaults.
- Domain tests own transformations and invariants. - CLI tests own argument mapping, streams, summaries, exit behavior, and
- Adapter tests own external integration behavior. representative command workflows.
- Orchestrator tests own coordination and failure propagation. - HTTP tests own DTOs, strict decoding, limits, status mapping, and restricted
- CLI tests own argument and configuration mapping. artifact policy.
- End-to-end tests prove that representative assembled workflows work. - 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. 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. 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. Increasing coverage is valuable only when the newly covered behavior protects a meaningful risk at an acceptable cost.

View File

@@ -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 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). [ADR 0003](../adr/0003-use-maintainer-run-validation-and-tag-only-releases-for-promptkit.md).
**Gate status:** Complete as of 2026-07-28. The **Gate status:** Complete as of 2026-07-28. Repository history records source
[Step 6 completion record](step6.md) records source Scriptorium commit Scriptorium commit `c7263ab2a8e58f7fb97280082d327a820c7cece7`,
`c7263ab2a8e58f7fb97280082d327a820c7cece7`, accepted Promptkit commit accepted Promptkit commit
`9e68a2bbf779545995270c47842048a3bc6c85dc`, independently passing acceptance, `9e68a2bbf779545995270c47842048a3bc6c85dc`, independently passing acceptance,
published annotated tag `v0.1.0`, and successful remote-consumer validation. published annotated tag `v0.1.0`, and successful remote-consumer validation.
Scriptorium remains unchanged at its pre-cutover boundary. Step 7 adoption of Scriptorium remains unchanged at its pre-cutover boundary. Step 7 adoption of