From 99d5e96316dface5e778806047d7536dfdf5f3ee Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Sun, 26 Jul 2026 18:46:42 -0500 Subject: [PATCH] Accept the Promptkit split architecture --- ...adopt-canonical-documentation-ownership.md | 5 +- .../0002-split-promptkit-from-scriptorium.md | 288 ++++++++++++++++++ docs/roadmap/migration.md | 13 +- 3 files changed, 298 insertions(+), 8 deletions(-) create mode 100644 docs/adr/0002-split-promptkit-from-scriptorium.md diff --git a/docs/adr/0001-adopt-canonical-documentation-ownership.md b/docs/adr/0001-adopt-canonical-documentation-ownership.md index e2a11e4..2af1b28 100644 --- a/docs/adr/0001-adopt-canonical-documentation-ownership.md +++ b/docs/adr/0001-adopt-canonical-documentation-ownership.md @@ -44,6 +44,5 @@ reviewable alongside the implementation change that requires them. - Changes to behavior must update the canonical owner in the same change. - Cross-cutting documentation links to the owner instead of copying its details. -- Documentation restructuring follows the implementation sequence in - [`docs/roadmap/documentation.md`](../roadmap/documentation.md); the roadmap, - not this ADR, records completion status. +- Documentation restructuring followed a dedicated implementation roadmap; + repository history, not this ADR, records its completion. diff --git a/docs/adr/0002-split-promptkit-from-scriptorium.md b/docs/adr/0002-split-promptkit-from-scriptorium.md new file mode 100644 index 0000000..8fba991 --- /dev/null +++ b/docs/adr/0002-split-promptkit-from-scriptorium.md @@ -0,0 +1,288 @@ +# ADR 0002: Split Promptkit From Scriptorium + +## Status + +Accepted + +## Date + +2026-07-26 + +## Context + +Scriptorium currently combines two products in one Go module: + +- a reusable prompt-execution framework with a public Go facade; and +- a runnable application with CLI and HTTP interfaces. + +Downstream Go projects increasingly import the framework directly and do not +use the executable interfaces. Keeping both products in one module couples +framework releases, dependencies, documentation, and public API evolution to +application-specific transport concerns. + +Promptkit will become the framework project, and Scriptorium will become a slim +application that consumes it. This ADR records that end-state boundary. It does +not assert that the split has been implemented; until then, the current +repository structure and contracts remain authoritative. + +## Decision + +### Projects And Module Paths + +Create a repository named `promptkit` alongside Scriptorium: + +| Project | Repository and Go module path | Root Go package | +| --- | --- | --- | +| Promptkit | `gitea.maximumdirect.net/eric/promptkit` | `promptkit` | +| Scriptorium | `gitea.maximumdirect.net/eric/scriptorium` | No reusable root facade after migration | + +Promptkit will expose its supported public API from the module root. Its +implementation packages will remain under `internal/` unless a real consumer +extension point requires a public type or interface. + +Scriptorium will import only Promptkit's supported public packages. It will not +import Promptkit implementation packages or reproduce Promptkit orchestration. + +### Product Responsibilities + +Promptkit owns application-neutral framework behavior: + +- the engine and its `Prepare` and `Run` workflow; +- public request, result, profile, option, extension, and error APIs; +- prompt-definition loading and rendering; +- profile loading, overlays, and the embedded built-in profile registry; +- schema loading and output validation; +- provider-neutral model-client boundaries and the OpenAI-compatible client; +- artifact types, artifact-reader injection, and general-purpose inline and + caller-selected file readers; +- execution-setting resolution and framework defaults; and +- framework-level secret redaction and error classification. + +Scriptorium owns executable and transport behavior: + +- the `scriptorium` process and its `run`, `render`, and `serve` commands; +- CLI parsing, streams, output files, formatting, exit codes, and process + cancellation behavior; +- application-configuration discovery and CLI-over-configuration precedence; +- HTTP routing, strict request decoding, DTO mapping, response encoding, + status codes, and transport limits; +- HTTP artifact-root containment and deployment policy; +- server construction, server defaults, and process logging; and +- executable release artifacts. + +The dependency direction is: + +```text +Scriptorium CLI and HTTP adapters + | + v + Promptkit public API + | + v + injected sources, readers, and model clients +``` + +### Current Package Disposition + +Implementation may reorganize files during extraction, but each current package +has this target owner: + +| Current package or file group | Target owner | Disposition | +| --- | --- | --- | +| Root `scriptorium` facade files and tests | Promptkit | Move and rename the public package to `promptkit`; Scriptorium retains no compatibility facade. | +| `internal/domain`, `internal/usecase` | Promptkit | Move as internal engine implementation. | +| `internal/promptdef`, `internal/prompt` | Promptkit | Move as internal prompt loading and rendering. | +| `internal/profile`, `internal/profile/builtin` | Promptkit | Move with embedded built-in assets and registry tests. | +| `internal/filecatalog` | Promptkit | Move as source-loading support. | +| `internal/validate` | Promptkit | Move as schema and output-validation implementation. | +| `internal/llm` | Promptkit | Move with the OpenAI-compatible integration. | +| `internal/artifact` | Split | Move general inline/file reading to Promptkit; keep rooted, denied, and byte-limited HTTP file reading in Scriptorium behind a Promptkit reader interface. | +| `internal/defaults` | Split | Move framework, execution, output-artifact, content-type, and model-client defaults to Promptkit; keep CLI, HTTP, and server defaults in Scriptorium. | +| `internal/adapter/cli`, `internal/adapter/http` | Scriptorium | Keep and refactor to use Promptkit's public API. | +| `internal/config` | Scriptorium | Keep application settings, discovery, validation, and CLI precedence. | +| `internal/format` | Scriptorium | Keep prepared-run presentation, rewritten against Promptkit public values. | +| `cmd/scriptorium` | Scriptorium | Keep as the process entrypoint. | + +Tests move with the behavior they protect. Cross-boundary tests will live with +the consuming side: Promptkit protects framework contracts, while Scriptorium +protects adapter mapping, HTTP containment, and executable behavior. + +### Public Boundary + +Promptkit's initial facade will preserve the useful shape of the current +Scriptorium Go API where that reduces extraction risk. It will expose only the +capabilities required by Promptkit consumers and by Scriptorium: + +- engine construction, preparation, and execution; +- public request, result, profile, and error values; +- prompt, profile, schema, artifact-reader, validator, and model-client source + or injection options that have demonstrated consumers; and +- enough stable error identity for Scriptorium to map CLI and HTTP outcomes. + +Promptkit will not export its domain package, runner implementation, +repositories, adapter DTOs, or general internal constructors merely to +simplify the move. + +Scriptorium's CLI and HTTP adapters will depend on a small consumer-facing +`Prepare`/`Run` interface where test substitution is needed. That interface +belongs at the consuming boundary rather than forcing adapter concepts into +Promptkit. + +### Artifact Reading And HTTP Containment + +Promptkit will define the artifact-reader extension point used during +preparation. Its ordinary file reader may read a path deliberately supplied by +an in-process or CLI caller and does not claim to be a deployment sandbox. + +Scriptorium will implement the HTTP-specific reader that: + +- denies file references when no artifact root is configured; +- applies the configured artifact byte limit; +- enforces Scriptorium's documented lexical root-containment rule; and +- maps reader failures to Scriptorium HTTP error responses. + +Scriptorium will inject that reader through Promptkit's public construction +boundary. Promptkit will not know about HTTP roots, status codes, request DTOs, +or deployment policy. + +### Configuration And Default Ownership + +Configuration ownership follows the behavior configured, not the current file +location: + +| Configuration category | Owner | +| --- | --- | +| Application configuration discovery, configuration-file precedence, `prompt_dir`, `profile_dir`, and `schema_dir` | Scriptorium | +| CLI flags and their mapping to application settings or request overrides | Scriptorium | +| `server.*`, render-output settings, HTTP byte limits, and server defaults | Scriptorium | +| Prompt-definition, profile, and output-contract file formats | Promptkit | +| Prompt/profile source selection, overlays, schema behavior, and built-in profiles | Promptkit | +| Execution settings, presence-aware request overrides, and execution defaults | Promptkit | +| Built-in OpenAI-compatible client settings, timeout behavior, and provider wire mapping | Promptkit | +| HTTP request and response fields, including their mapping to framework values | Scriptorium | + +Scriptorium will translate its application settings and external request +values into Promptkit construction options and requests. When an omitted +Scriptorium setting means “use the framework default,” Scriptorium will omit +the override rather than copy Promptkit's numeric default. + +### Compatibility And Versioning + +This migration is intentionally breaking: + +- new Go consumers will import `gitea.maximumdirect.net/eric/promptkit`; +- Scriptorium will not provide aliases, forwarding wrappers, or deprecated + compatibility packages for its former Go facade; +- existing consumers may remain pinned to the final framework-bearing + Scriptorium tag until migrated; and +- intermediate migration phases need not preserve source compatibility, but + each merged phase must be internally buildable and tested. + +Promptkit's first release will be `v0.1.0`. During the migration, incompatible +Promptkit changes may advance its minor version until a stable `v1` contract is +declared. The first slim Scriptorium release will advance the Scriptorium minor +version beyond the final framework-bearing release. Normal semantic-versioning +rules apply independently to both projects after the migration. + +Promptkit must be tagged before Scriptorium or another consumer publishes a +release that depends on it. Release branches must use tagged module +dependencies, not local replacements or unpublished revisions. + +### Local Development And Cross-Repository Coordination + +For coordinated local work, place both repositories in a temporary Go +workspace or use an uncommitted module replacement. `go.work`, +`go.work.sum`, and local filesystem `replace` directives must not be committed +to release branches. + +Cross-repository changes follow this order: + +1. land and tag the required Promptkit capability; +2. update Scriptorium and other consumers to that tag; +3. run each repository's own CI and smoke checks; and +4. release consumers only after the Promptkit tag is available. + +Migration coordination must confirm out-of-band repository creation, Promptkit +tags, and downstream migrations before dependent work proceeds. +Cross-repository changes are coordinated, not treated as atomic commits. + +### Documentation And Maintained Assets + +Each repository will maintain its own README, contributor guide, architecture, +documentation, testing, release, and operations material appropriate to that +project. Cross-project documents will link to the canonical owner rather than +copy its contract. + +Existing documentation and maintained assets have these target owners: + +| Current material | Target owner | +| --- | --- | +| Current README and executable quickstart | Scriptorium; Promptkit creates its own framework orientation | +| Public Go package and Go-consumer guidance | Promptkit | +| Prompt, profile, schema, execution-setting, and framework credential reference | Promptkit | +| OpenAI-compatible integration contract and framework internal documents | Promptkit | +| CLI, HTTP API, subprocess, and Scriptorium operations contracts | Scriptorium | +| Consumer interface overview | Scriptorium, revised to route Go consumers to Promptkit | +| Application-configuration discovery, server settings, and adapter internals | Scriptorium | +| Current internal overview and source documentation | Split into repository-local overviews; Promptkit owns framework sources and Scriptorium owns HTTP containment | +| This ADR and cross-project migration records | Scriptorium | +| `examples/go-library` | Promptkit | +| `examples/config*.yml`, `examples/render-markdown-summary.sh`, and `examples/http-run.json` | Scriptorium | +| Example prompts, profiles, schemas, and synthetic fixtures used by the executable examples | Scriptorium | +| Embedded built-in profile assets | Promptkit | +| Scriptorium release workflow and executable packaging | Scriptorium | +| Repository-level license, ignore rules, agent guidance, and development policies | Each repository maintains its own applicable copy | + +Promptkit will create or retain its own minimal framework examples and test +fixtures rather than making either repository's tests depend on the other's +working tree. Scriptorium's framework-format documentation will become a short +version-appropriate link to Promptkit, while its maintained executable examples +remain self-contained. + +## Alternatives Considered + +- Keep the current combined repository and improve package naming. This avoids + migration work but retains release and ownership coupling between the + framework and executable. +- Add Promptkit as a wrapper around the Scriptorium public package. This gives + consumers a new import path but leaves framework ownership and dependency + direction inverted. +- Extract Promptkit while retaining a Scriptorium compatibility facade. This + reduces immediate consumer changes but creates a second public API surface + and prolongs duplicate maintenance. +- Move all artifact reading into Promptkit. This would place HTTP containment, + byte limits, and deployment policy in the application-neutral framework. +- Keep Promptkit and Scriptorium as separate modules in one repository. This + separates imports but not repository permissions, release workflows, + issue ownership, or independent project evolution. + +## Rationale + +A separate Promptkit project makes the reusable framework the direct owner of +the API that downstream Go projects already consume. Keeping Scriptorium as a +public-API consumer exercises the same boundary as other consumers and prevents +its adapters from relying on framework internals. + +The selected split keeps transport and deployment policy close to the +Scriptorium interfaces that expose it, while allowing Promptkit to remain +useful to in-process consumers with different IO and security requirements. +Explicit package, configuration, documentation, and asset ownership reduces +ambiguity during extraction and after release. + +## Consequences + +- All Go consumers of the framework must change their import path. +- Promptkit and Scriptorium gain independent issue, release, CI, policy, and + documentation lifecycles. +- Scriptorium becomes a real downstream integration test of Promptkit's public + facade. +- Framework changes that affect Scriptorium require tagged, ordered + cross-repository coordination. +- Some current packages, especially artifact reading and defaults, must be + separated by responsibility rather than moved intact. +- Scriptorium's current configuration and documentation references must be + split between application and framework owners. +- Maintainers must inventory and migrate downstream consumers explicitly; no + compatibility facade will hide incomplete migration. +- Until the split is implemented, the current repository structure and + contracts remain authoritative. diff --git a/docs/roadmap/migration.md b/docs/roadmap/migration.md index f216c3d..05df3e4 100644 --- a/docs/roadmap/migration.md +++ b/docs/roadmap/migration.md @@ -2,8 +2,8 @@ ## Status -Accepted plan. Step 1, the documentation refresh, is complete. Steps 2 through -9 remain proposed and are not yet implemented. +Accepted plan. Steps 1 and 2 are complete. Steps 3 through 9 remain proposed +and are not yet implemented. ## Objective @@ -94,9 +94,8 @@ refresh and policy updates are merged and the repository has an agreed, accurate baseline. **Gate status:** Complete as of 2026-07-26. The completed documentation -refresh, follow-up verification, and layered-timeout correction record are in -the [documentation compliance roadmap](documentation.md). Step 1 remains -complete after that validation. +refresh, follow-up verification, and layered-timeout correction remain recorded +in repository history. Step 1 remains complete after that validation. ### Step 2: Record The Architectural Decision And Detailed Boundary @@ -117,6 +116,10 @@ moved. **Gate:** The ADR is accepted, and every existing package, public contract, configuration category, and maintained asset has a target owner. +**Gate status:** Complete as of 2026-07-26. +[ADR 0002: Split Promptkit From Scriptorium](../adr/0002-split-promptkit-from-scriptorium.md) +is accepted and records the required ownership and coordination decisions. + ### Step 3: Characterize Existing Framework Behavior Strengthen or add contract-focused tests where needed so extraction can be