Files
scriptorium/docs/roadmap/implementation.md

24 KiB

Step 7 Implementation Plan

Status

Accepted for implementation.

Implement each stage in order. Do not begin a later stage until the current stage's exit criteria pass. The Step 7 feature roadmap is the north star for scope, policy, desired behavior, and completion. ADR 0002 controls the durable project boundary.

This plan changes Scriptorium only. Promptkit v0.1.0 is a published, read-only input to the cutover. Do not edit Promptkit, create a new Promptkit tag, or use the sibling Promptkit checkout to make an intermediate Scriptorium state pass.

Implementation Rules

Apply these rules throughout every stage:

  • Read both repositories' development, architecture, documentation, and testing policies before implementation.
  • Preserve unrelated working-tree changes. The removals of completed roadmap files that predate this plan are user-owned changes and must not be restored.
  • Run Scriptorium commands outside a Go workspace. Do not commit go.work, go.work.sum, a local replace, vendored Promptkit source, or generated dependency output.
  • Depend only on gitea.maximumdirect.net/eric/promptkit v0.1.0 and its root promptkit package. Do not import promptkit/internal/....
  • Treat the former Scriptorium Go package as intentionally removed. Do not add aliases, forwarding wrappers, deprecated shims, or an application-local copy of Promptkit values.
  • Preserve CLI, HTTP, configuration, formatting, artifact-containment, security, error-mapping, and process behavior unless the feature roadmap explicitly says otherwise.
  • Prefer adapting existing application tests to Promptkit values over adding parallel test suites. Delete tests whose only owner is the removed framework.
  • Keep permanent documentation aligned with implemented state. Do not describe a later stage as complete before its code has landed.
  • Use gofmt for Go formatting and go mod tidy for module metadata. Do not hand-edit go.sum.

If a required capability is absent from Promptkit v0.1.0, stop the Step 7 implementation and report the exact public-boundary gap. Do not work around it with a Scriptorium framework copy or an unpublished Promptkit revision.

Stage 1: Cut The Application Seam Over To Promptkit

Objective

Make all retained Scriptorium application code and tests consume the published Promptkit facade while the old local framework remains temporarily available for comparison. This stage proves that v0.1.0 is sufficient before deleting the old implementation.

Module Dependency

Add an exact direct requirement:

gitea.maximumdirect.net/eric/promptkit v0.1.0

Resolve it from the configured module source with GOWORK=off. Do not add a replacement. Do not prune the old framework-only dependencies yet; the local framework still compiles during this stage.

Confirm before changing imports that the selected module resolves to v0.1.0 and that its origin hash is the accepted Promptkit release commit 9e68a2bbf779545995270c47842048a3bc6c85dc.

Production Import And Type Migration

Replace the former root-package import with gitea.maximumdirect.net/eric/promptkit in every retained application package. Use the package name promptkit in code rather than aliasing it back to scriptorium.

Update internal/adapter/cli/run.go so:

  • engine construction calls promptkit.NewEngine with promptkit.Config;
  • run and render requests use promptkit.RunRequest;
  • input mappings use promptkit.File and Promptkit artifact references;
  • execution overrides use promptkit.ExecutionTargetOverride;
  • the serve path injects the HTTP reader with promptkit.WithArtifactReader;
  • result summaries, validation classification, and exit-code selection use Promptkit result and status values; and
  • no CLI flag, precedence, output, or error wording changes solely because of the import migration.

Update internal/adapter/http so:

  • the adapter-owned Runner interface accepts promptkit.RunRequest and returns *promptkit.RunResult;
  • DTO mapping constructs Promptkit artifact references and execution overrides;
  • response mapping reads Promptkit artifact, validation, model, usage, and metadata values directly;
  • HTTP error mapping uses Promptkit's public sentinel errors with errors.Is; and
  • the restricted reader implements promptkit.ArtifactReader and uses Promptkit artifact reference, artifact, and reference-type values.

Keep ErrFileNotAllowed, ErrFileOutsideRoot, and ErrFileTooLarge in Scriptorium. Confirm that Promptkit's artifact-load wrapping preserves those underlying identities so the existing HTTP mappings continue to work.

Update internal/format so every formatter interface, entry point, message collection, and test fixture uses Promptkit prepared-run and message values directly.

Test Migration

Update retained CLI, HTTP, restricted-reader, and formatter tests to import and construct Promptkit public values. In particular:

  • fake runners must use the Promptkit request/result signature;
  • handler integration helpers must construct a real promptkit.Engine;
  • test LLM clients must implement promptkit.LLMClient;
  • engine options must use Promptkit options;
  • error-mapping tables must use Promptkit sentinels; and
  • formatting fixtures must use Promptkit public prepared-run types.

Do not change expected CLI output, HTTP payloads, status codes, error codes, artifact policy, or formatted render output merely to accommodate the new package name.

Validation

Run:

go mod download gitea.maximumdirect.net/eric/promptkit@v0.1.0
go list -m -f '{{.Path}} {{.Version}}' gitea.maximumdirect.net/eric/promptkit
go test ./internal/adapter/... ./internal/format/...
go test ./...
go vet ./...
go build ./cmd/scriptorium

Also run the maintained render script and the existing CLI command tests that exercise built-in profiles, custom profiles, explicit zero-valued overrides, restricted HTTP artifacts, public error mapping, and prepared-run formatting.

Exit Criteria

  • All retained application production code uses Promptkit public types.
  • Application tests use Promptkit at the same boundaries as production.
  • The exact direct v0.1.0 dependency is selected without a replacement.
  • The full repository still builds and tests while the local framework copy is present but unused by retained application code.
  • No Promptkit API gap has been discovered.

Stage 2: Remove The Duplicated Framework

Objective

Delete every Promptkit-owned implementation, facade, test, fixture, and example from Scriptorium, then reduce application defaults and module dependencies to the slim repository boundary.

Remove The Former Root Package

Delete the complete former root facade:

  • artifact_reader.go
  • artifact_reader_internal_test.go
  • convert.go
  • engine.go
  • engine_test.go
  • errors.go
  • formatting.go
  • json_copy.go
  • llm_adapter.go
  • profiles.go
  • types.go

After deletion, the Scriptorium module root must contain no .go files and must not be importable as package gitea.maximumdirect.net/eric/scriptorium. Do not replace these files with a stub package or migration shim.

Remove Promptkit-Owned Internal Packages

Delete these directories in full, including their package tests, testdata, and embedded assets:

  • internal/artifact
  • internal/domain
  • internal/filecatalog
  • internal/llm
  • internal/profile
  • internal/prompt
  • internal/promptdef
  • internal/usecase
  • internal/validate

Delete testdata/framework. Promptkit owns the framework contract corpus and already contains its maintained copy.

Delete examples/go-library. The Scriptorium Go-library example is obsolete; Promptkit owns the maintained in-process preparation example.

Do not delete the executable assets under examples/config*.yml, examples/prompts, examples/profiles, examples/schemas, examples/fixtures, examples/http-run.json, or examples/render-markdown-summary.sh. Those remain Scriptorium application examples even though Promptkit owns their file-format semantics.

Split Defaults By Ownership

Reduce internal/defaults/defaults.go to values still owned and used by Scriptorium:

  • HTTPAddrDefault
  • SchemaDirDefault, which remains the application configuration default for Scriptorium's schema source location;
  • HTTPMaxRequestBytesDefault
  • HTTPMaxArtifactBytesDefault
  • HTTPMaxResponseBytesDefault; and
  • HTTPReadHeaderTimeoutDefault.

Remove framework-owned output-artifact names, content types, OpenAI-compatible paths, execution defaults, model-client timeouts, domain imports, and ExecutionTargetDefault.

Do not copy constants from Promptkit merely to make tests convenient. When the CLI does not supply a framework setting, continue passing the zero value so Promptkit applies its own default.

Prune Module Metadata

Run go mod tidy only after all Promptkit-owned source and tests are gone. Keep gopkg.in/yaml.v3 as a direct dependency because Scriptorium still decodes application configuration. Allow go mod tidy to remove or reclassify JSON Schema and other modules according to the actual remaining import graph.

The final go.mod must have:

  • Promptkit v0.1.0 as a direct dependency;
  • no replace directive;
  • no dependency retained solely for deleted framework code; and
  • the existing compatible Go language version.

Validation

Run:

go mod tidy
go list ./...
go test ./...
go vet ./...
go build ./cmd/scriptorium

Inspect go list ./... and the filesystem. The package inventory must consist only of the command and retained application packages: adapters, configuration, defaults, and formatting. The module root and removed framework package families must be absent.

Exit Criteria

  • Scriptorium exposes no root Go package.
  • No duplicated framework package, built-in registry, framework testdata, or Go-library example remains.
  • Application defaults contain no Promptkit-owned behavior.
  • Module metadata reflects the actual slim application graph.
  • All remaining packages test, vet, and build against Promptkit v0.1.0.

Stage 3: Harden The Boundary And Rationalize Tests

Objective

Make the slim dependency direction durable and leave Scriptorium with a lean test suite that protects application behavior rather than retesting Promptkit.

Architecture Guard

Rewrite internal/adapter/dependency_test.go as a repository-level application-boundary guard. It may remain in the internal/adapter test package, but it must locate the module root reliably and recursively inspect all non-test production .go files under the repository.

The scanner must:

  • skip .git, vendor, and other non-source output directories;
  • parse imports with the Go parser instead of searching raw source text;
  • reject the exact former root import gitea.maximumdirect.net/eric/scriptorium;
  • reject the former Scriptorium framework package families removed in Stage 2;
  • reject gitea.maximumdirect.net/eric/promptkit/internal and every path below it; and
  • continue allowing retained Scriptorium application-internal imports such as internal/config, internal/defaults, internal/format, and adapter packages.

Add focused scanner tests using temporary nested source trees to prove exact root-package detection, nested former-family detection, Promptkit-internal detection, and allowance of retained application packages.

Add an architecture assertion that:

  • the module root has no production .go file; and
  • each removed framework directory is absent.

This is an intentional architecture invariant, not a generic assertion that the whole repository tree can never change.

Test Ownership Audit

Review every remaining test after the mechanical import migration:

  • internal/adapter/cli owns CLI parsing, configuration/flag mapping, command output, summaries, exit codes, and representative real-engine command workflows;
  • internal/adapter/http owns DTO mapping, strict JSON, status/error mapping, limits, restricted artifact policy, cancellation, and representative real-engine handler workflows;
  • internal/config owns strict application YAML, discovery, precedence, validation, and application defaults;
  • internal/format owns deterministic text/JSON presentation; and
  • the architecture guard owns dependency direction and removal invariants.

Retain the existing real Promptkit-engine adapter tests because they protect the consumer integration seam. Keep their prompt and profile fixtures package-local or generated with t.TempDir; do not recreate testdata/framework.

Delete or simplify any assertion that only duplicates Promptkit parser, orchestration, profile, validation, model-client, or public-contract tests. Do not add a Scriptorium table for every Promptkit sentinel or field. Preserve only mappings Scriptorium exposes through CLI or HTTP behavior.

Add a new test only when the cutover exposes an application-owned risk that is not already covered. Prefer updating an existing adapter integration test over creating a new end-to-end harness.

Release Workflow Check

Inspect .woodpecker/release.yml and any packaging metadata for assumptions about the removed root package or framework directories. Keep the release target at ./cmd/scriptorium (or its canonical module package path) and ensure the workflow obtains Promptkit through ordinary module resolution.

Do not add a Promptkit checkout, workspace, replacement, vendor step, or cross-repository artifact to Scriptorium CI or release packaging.

Validation

Run:

go test ./...
go test -race ./...
go vet ./...
go build ./cmd/scriptorium

Run the architecture guard directly by name as a focused diagnostic. Confirm that its negative fixtures fail the scanner for the intended import and that the real repository produces no violation.

Exercise the release workflow's Go build commands locally with temporary outputs for its supported target platforms. Do not create dist/ or another tracked output directory during validation.

Exit Criteria

  • The repository guard protects the complete new dependency direction.
  • Remaining tests have an explicit application-owned purpose.
  • No deleted Promptkit behavior is redundantly reimplemented in tests or fixtures.
  • Race-enabled tests, vet, application builds, and release-equivalent builds pass.

Stage 4: Reconcile Permanent Documentation And Examples

Objective

Make all permanent Scriptorium documentation describe the implemented slim application and route framework readers to the version of Promptkit the application actually consumes.

Use the tagged Promptkit v0.1.0 documents as the canonical framework references during this step. Link to the corresponding files under:

https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.1.0/

Use these owners where applicable:

  • docs/consumers/pkg-promptkit.md for Go-library consumer guidance;
  • docs/formats.md for prompt, profile, schema, execution-setting, built-in profile, and framework credential contracts; and
  • docs/integrations/openai-compatible-chat.md for outbound provider wire and timeout behavior.

Do not copy their field tables, defaults, error inventories, or timeout rules into Scriptorium. Scriptorium documents only its own mapping or invocation surface and links to the Promptkit owner for the framework definition.

Orientation And Policy

Update:

  • README.md to present only the runnable CLI and HTTP application, remove the Scriptorium Go-package link and Go-library example, and identify Promptkit as the imported framework;
  • docs/policy/architecture.md to define the current application-only shape, retained package boundaries, Promptkit dependency direction, HTTP artifact security boundary, application invariants, and non-goals;
  • docs/development.md to route contributors to the remaining adapter, configuration, formatting, packaging, and Promptkit-consumer boundaries;
  • docs/policy/documentation.md where its ownership table or boundary rules still imply that Scriptorium owns a public Go package or framework integration; and
  • docs/policy/testing.md where framework-domain, validator, model-client, or orchestration examples imply those are still Scriptorium test owners.

Do not rewrite accepted ADR decision content. ADR 0002 remains the permanent decision record even where its context describes the pre-split state.

External And User Contracts

Audit and update:

  • docs/cli.md
  • docs/api.md
  • docs/config.md
  • docs/operations.md
  • docs/consumers/api.md
  • docs/integrations/subprocess.md

Preserve Scriptorium-owned command syntax, configuration discovery and server fields, HTTP schemas and mappings, operations, and subprocess behavior. Remove claims that Scriptorium provides an in-process Go API. Where these documents name prompt/profile fields, model semantics, built-in profiles, framework credentials, or timeout behavior, keep only the Scriptorium mapping context and link to the tagged Promptkit owner.

Delete docs/consumers/pkg-scriptorium.md. Update every incoming link so Go framework consumers are directed to Promptkit rather than to a compatibility document.

Delete docs/integrations/openai-compatible-chat.md after replacing all incoming Scriptorium links with the tagged Promptkit integration contract. Scriptorium no longer owns the outbound provider protocol.

Internal Documentation

Update docs/internal/overview.md to inventory exactly:

  • cmd/scriptorium;
  • internal/adapter/cli;
  • internal/adapter/http;
  • internal/config;
  • internal/defaults; and
  • internal/format.

Update docs/internal/adapters.md for Promptkit request/result mapping, engine construction, consumer-owned interfaces, error mapping, output behavior, and restricted-reader injection.

Rewrite docs/internal/sources.md around Scriptorium-owned application source locations and the restricted HTTP artifact reader. Link Promptkit for ordinary artifact loading and framework source semantics.

Delete:

  • docs/internal/runner.md
  • docs/internal/llm.md

Promptkit owns those subsystem documents. Remove all incoming links rather than leaving placeholder internal documents.

Examples And Navigation

Keep the executable configuration, prompt, profile, schema, fixture, HTTP, and render-script examples. Confirm they still run against the tagged dependency and that prose describes them as Scriptorium application examples.

Remove every link to examples/go-library, root Go declarations, removed framework directories, deleted Scriptorium consumer documentation, and deleted internal or integration documents.

Search all permanent Markdown outside docs/roadmap/ for:

  • the former root import path used as a Go package;
  • claims that Scriptorium owns or implements the framework;
  • references to removed packages, tests, fixtures, or examples; and
  • duplicate Promptkit framework contracts.

The migration roadmap and accepted ADRs may retain historical and future language appropriate to their lifecycle.

Validation

Validate every local Markdown link and follow every new external Promptkit link. Run:

git diff --check
go test ./...
go vet ./...
go build ./cmd/scriptorium

Run the maintained render script and both examples/config.yml and examples/config.full.yml through a credential-free render workflow. No documentation validation may invoke a paid or live model endpoint.

Exit Criteria

  • Permanent docs describe only the implemented application boundary.
  • Framework contracts have one Promptkit owner and version-appropriate links.
  • Removed code and examples have no live incoming links.
  • All retained examples are valid, secret-free, and runnable offline where intended.
  • Documentation links, whitespace, tests, vet, and the executable build pass.

Stage 5: Perform Independent Acceptance And Record Completion

Objective

Validate the exact final state without sibling-repository coupling, then record the Step 7 gate only after every feature-roadmap completion criterion is satisfied.

Scriptorium Acceptance

From the Scriptorium repository root, confirm no Go workspace is active and no replacement or vendored dependency exists. Validate module identity and selection:

go list -m -f '{{.Path}} {{.GoVersion}}'
go list -m -f '{{.Path}} {{.Version}}' gitea.maximumdirect.net/eric/promptkit
go mod graph
go mod tidy -diff

Require the Scriptorium module path and existing Go version, and require Promptkit to resolve exactly to v0.1.0. Inspect the graph for a normal tagged module edge rather than a local path.

Run:

go test ./...
go test -race ./...
go vet ./...
go build ./cmd/scriptorium
gofmt -l $(git ls-files '*.go')
git diff --check

The formatting command must produce no paths. Build the executable to a temporary directory rather than the repository. Reproduce the release workflow's supported cross-compilation targets and linker flags with temporary outputs.

Run the maintained render script and credential-free render commands using both configuration examples. Verify representative HTTP behavior through the retained handler tests, including strict decoding, request/response size limits, restricted file access, public error mapping, and optional raw output.

Validate all maintained Markdown links, including the tagged Promptkit links. Search the final tracked tree for former root-facade imports, removed framework packages, built-in asset copies, framework fixtures, Go-library examples, workspaces, replacements, generated binaries, credentials, and stale documentation references.

Clean Remote-Dependency Verification

Use a fresh temporary module cache with GOWORK=off and ordinary remote module resolution to download dependencies and run at least the Scriptorium build and test suite. The verification must not read the sibling Promptkit working tree. Confirm the downloaded Promptkit module reports version v0.1.0 and origin commit 9e68a2bbf779545995270c47842048a3bc6c85dc.

Do not clear or destructively rewrite the maintainer's normal module cache. Use a temporary directory and remove it after validation.

Independent Promptkit Reconfirmation

Without changing Promptkit, validate the exact v0.1.0 source from a temporary detached worktree or the downloaded module directory. If the clean Promptkit checkout still has HEAD exactly at the peeled v0.1.0 commit, it may be used directly. Run Promptkit's documented sequence from that exact source:

go test ./...
go test -race ./...
go vet ./...
go build ./...
go run ./examples/go-library/prepare

Also check Promptkit formatting, links, whitespace, module tidiness, absence of a workspace/replacement, clean status, and the local and remote v0.1.0 tag target. Remove any temporary detached worktree after validation. This proves that Scriptorium's adoption did not introduce cross-repository state or require an unpublished Promptkit change.

Completion Records

Only after all acceptance checks pass:

  • update docs/roadmap/step7.md status from Proposed to Complete and replace future-oriented starting-state material as needed with a concise result, retained application boundary, validation evidence, and Step 8 handoff;
  • update docs/roadmap/migration.md so its status says Steps 1 through 7 are complete and its Step 7 gate records the tagged dependency, removal of the framework copy and public facade, independent validation, and readiness for downstream migration; and
  • replace this staged checklist with a concise Step 7 implementation completion record containing the dependency version, resulting package boundary, removed ownership, validation evidence, and next gate.

Do not mark Step 8 or Step 9 complete. Do not publish a Scriptorium release or claim that external consumers have migrated.

Exit Criteria

  • Every completion criterion in docs/roadmap/step7.md is demonstrably true.
  • Scriptorium passes release-grade validation against remotely resolved Promptkit v0.1.0.
  • Promptkit remains independently clean and valid at its published tag.
  • Permanent documentation, examples, module metadata, and architecture checks match the final slim application.
  • Completion records accurately authorize Step 8 without claiming later work.