# Step 9 Implementation Plan ## Status Complete as of 2026-07-28. ## Completion Summary Promptkit's annotated `v0.1.0` tag remains published at commit `9e68a2bbf779545995270c47842048a3bc6c85dc`. Scriptorium's annotated `v0.12.0` tag object `734632371773bb7620ce9f18e79ae179a2a2b44b` resolves to independently validated commit `2f42bdde3957563cb9b7a1e27fdd4ab2516f621a`. The [hosted release](https://gitea.maximumdirect.net/eric/scriptorium/releases/tag/v0.12.0) succeeded with release notes matching the checked-in source, exactly the Linux `amd64` and `arm64` binaries, and verified SHA-256 checksums. Fresh remote module resolution and independent repository validation passed without sibling-repository state. The downloaded `amd64` binary completed an offline render; its existing command interface treated `--help` as an unknown command and printed usage. The `arm64` binary could not be executed on the `amd64` host, so its checksum, format, and target architecture were verified. Notarius at commit `de046a8f13e227676d79c3aa3b685b049902038d` remains migrated and verified, and no other downstream Go consumer was identified. All three repositories were clean and synchronized after validation. This plan implements the target state and policy decisions in [Step 9](step9.md). Execute the stages in order. A later stage may begin only after the preceding stage's completion checks pass and any required cross-repository commit is published. ## Fixed Decisions And Baseline - Promptkit `v0.1.0` at commit `9e68a2bbf779545995270c47842048a3bc6c85dc` is the published framework baseline. Do not create a new Promptkit tag for documentation-only work. - Scriptorium `v0.11.1` is the final framework-bearing release. - Scriptorium `v0.12.0` is the intended first application-only release. - Scriptorium will not restore a Go facade, compatibility package, alias, or forwarding API. - Promptkit retains maintainer-run validation and tag-only source releases. Do not add hosted Promptkit CI or binary packaging. - Scriptorium retains hosted, tag-triggered Linux `amd64` and `arm64` binary releases with SHA-256 checksums. - Versioned Scriptorium release notes live at `docs/releases/.md`. The release workflow copies the file matching `CI_COMMIT_TAG` into its build workspace and supplies that copy to the Woodpecker release plugin's documented [`note` setting](https://woodpecker-ci.org/plugins/release). - The obsolete linker assignment to the removed `internal/buildinfo.Version` symbol is deleted. Do not introduce a version command or replacement build-information package. - Temporary roadmaps remain present through tag and hosted-release verification. They are removed only after completion is recorded in Git history. Repository paths for this work are: - Scriptorium: `/Users/eric/Code/scriptorium/scriptorium` - Promptkit: `/Users/eric/Code/scriptorium/promptkit` - Notarius verification checkout: `/Users/eric/Code/notarius` Do not commit `go.work`, `go.work.sum`, a `replace` directive, vendored Promptkit source, generated binaries, downloaded release assets, credentials, or temporary validation output. Use directories created with `mktemp -d` for clones, caches, builds, and downloads, and remove or leave those directories outside the repositories. ## Stage 1: Correct Promptkit Release And Project Documentation Work only in the Promptkit repository during this stage. ### Changes 1. Rewrite `docs/release.md` as a current, reusable procedure: - state that `v0.1.0` is the initial published release rather than a planned tag; - retain semantic `vMAJOR.MINOR.PATCH` tags, pre-`v1` compatibility notes, maintainer-run validation, and source-only publication; - require the maintainer to provide a not-yet-published `RELEASE_VERSION`, validate it as a semantic version, and derive the release commit from `HEAD`; - retain clean-checkout, no-workspace, no-replacement, module identity, tests, race tests, vet, build, maintained example, formatting, link, whitespace, and repository-hygiene checks; - use the annotated tag message as Promptkit's source-only release notes, recording the version, validated commit, compatibility summary, public API changes, and any required consumer action; - retain annotated-tag creation, exact-ref publication, remote tag-object comparison, source-commit verification, and ordinary Go module resolution checks; and - state the Promptkit-before-consumer release ordering without restating Scriptorium's release procedure. 2. Use guarded shell examples. A missing or already-existing release version, a dirty checkout, an active workspace, a replacement, an unpushed release commit, or an existing local or remote tag must stop the procedure before tag creation. Publish only the selected tag ref, never all local tags. 3. Add a short “Related project” entry to Promptkit's `README.md` linking to the Scriptorium repository as the CLI and HTTP application built on Promptkit. Do not copy Scriptorium invocation or transport contracts into Promptkit. 4. Audit Promptkit README, consumer, architecture, development, and internal documents for stale extraction or pre-release language. Change only claims that are no longer true; exact public API and format contracts remain with their existing canonical owners. ### Validation - Follow every changed local and cross-project Markdown link. - Check all changed shell fragments for valid POSIX shell syntax without executing tag or push commands. - Run `git diff --check`. - Confirm no code, module, example, architecture boundary, or public contract changed. ### Completion State Commit the Promptkit documentation changes with a plain-English message and push the commit to `origin/main`. Require a clean Promptkit working tree with `main` synchronized to `origin/main` before Stage 2. Do not create a Promptkit tag. ## Stage 2: Establish Scriptorium Release Ownership And Mechanics Work only in the Scriptorium repository during this stage. ### Documentation Ownership 1. Add two canonical-owner rows to `docs/policy/documentation.md`: - `docs/release.md` owns the Scriptorium release procedure, including candidate validation, version and tag operations, hosted-workflow observation, and artifact verification; - `docs/releases/` owns immutable version-specific release notes and migration announcements, not complete interface contracts. 2. Update the release-packaging row in `docs/development.md` to route contributors to `docs/release.md`, `.woodpecker/release.yml`, and the architecture policy. 3. Create `docs/release.md` with an end-to-end procedure for: - selecting `v0.12.0` for this release and a semantic version for later releases; - requiring a clean, pushed release commit on `main`, outside a Go workspace and without a module replacement or vendor tree; - confirming module identity, Go version, direct Promptkit version, module graph, module tidiness, and tag availability; - running the complete application and release-equivalent validation defined in Stage 4; - requiring `docs/releases/.md`; - creating and inspecting an annotated tag bound to the validated commit; - pushing only that exact tag ref; - monitoring the hosted workflow; - comparing local and remote tag objects and commits; - downloading and verifying release assets and checksums; and - handling failures without moving or recreating a published tag. The procedure must distinguish an unreleased candidate from a verified published release and must not claim that `v0.12.0` exists before its tag and hosted artifacts are confirmed. 4. Keep operator workflows in `docs/operations.md`; add a release-procedure link there only if a concrete operator task needs it. ### Release Workflow Update `.woodpecker/release.yml` as follows: 1. Keep tag-only execution, Go `1.25`, `CGO_ENABLED=0`, `-trimpath`, `-s -w`, the existing Linux architectures, filenames, release plugin, and checksum policy. 2. Remove only the stale `-X gitea.maximumdirect.net/eric/scriptorium/internal/buildinfo.Version=...` linker assignment. 3. Before building, require a release-notes source at `docs/releases/$CI_COMMIT_TAG.md`. Fail with a clear diagnostic when it is absent. 4. Copy that source to a stable path under the workflow's `dist` directory, such as `dist/RELEASE_NOTES.md`. 5. Set the release plugin's `note` value to the copied file. Keep release-note content out of the binary asset glob so only the two binaries are checksummed and uploaded alongside `SHA256SUMS`. 6. Preserve `overwrite: false` and non-prerelease publication. Do not add automatic tag generation or release mutation. Do not add a Go test that parses or snapshots the workflow. The material risks are protected by release-equivalent builds, missing-note failure behavior, hosted execution, and artifact inspection. ### Validation - Inspect the YAML and embedded shell for the exact intended paths and dependency between build and publish steps. - In a temporary directory, reproduce the build step with `CI_COMMIT_TAG=v0.12.0` and a temporary output directory. Confirm both release-equivalent binaries build and the release-note selection fails for a nonexistent tag. - Use `file` or an equivalent binary inspector to confirm Linux `amd64` and Linux `arm64` targets. - Run `git diff --check` and validate all new local documentation links. ### Completion State The release contract and workflow are internally consistent, reusable after `v0.12.0`, and contain no reference to a removed package. Do not tag or publish Scriptorium in this stage. ## Stage 3: Publish Migration Guidance And Release Notes Work only in the Scriptorium repository during this stage. ### Go Consumer Migration Guide Create `docs/consumers/migrating-to-promptkit.md` as the canonical guide for leaving the former Scriptorium Go package. It must: 1. Identify Scriptorium `v0.11.1` and `gitea.maximumdirect.net/eric/scriptorium` as the source, Promptkit `v0.1.0` and `gitea.maximumdirect.net/eric/promptkit` as the destination, and Scriptorium `v0.12.0` as executable-only. 2. Give copyable commands that: - add Promptkit `v0.1.0`; - replace Go imports and package qualifiers; - remove the old Scriptorium dependency through `go mod tidy`; and - run the consumer's tests. 3. Explain at a high level that the established engine, requests, results, profiles, source options, model-client boundary, artifacts, validation values, and error identities were preserved where practical. 4. Identify the Promptkit additions relevant to migration: `WithArtifactReader`, `ArtifactReader`, `ErrProfileRequired`, and `ErrAPIKeyEnvMissing`. Link exact declarations and behavior to Promptkit's tagged consumer guide and Go source rather than reproducing them. 5. Tell consumers to verify the behavior they actually rely upon, including configuration sources, credentials, timeout layering, validation, injected extensions, and `errors.Is` handling. 6. State that no compatibility facade exists. Consumers unable to migrate may remain pinned to Scriptorium `v0.11.1`, but that line does not provide the slim application release. ### Scriptorium Navigation 1. Add the migration guide to the documentation list in `README.md`. 2. Add a concise link from `docs/consumers/api.md` for readers arriving from the former Go API. 3. Audit all Scriptorium Markdown and Go package comments: - current product statements must describe a CLI and HTTP application; - framework contracts must link to tagged Promptkit `v0.1.0` owners; - no permanent document may imply that Scriptorium still exports a Go package; - no document may copy Promptkit's exact fields, defaults, or API declarations merely to explain the split. 4. Keep general cross-project navigation pointed at project entry pages and contract links pinned to the consumed Promptkit tag. ### Versioned Release Notes Create `docs/releases/v0.12.0.md`. Write it so the same Markdown works both as a checked-in document and as the hosted release body. It must: - identify the executable-only boundary as a breaking change; - direct former Go consumers to the migration guide and Promptkit `v0.1.0`; - identify `v0.11.1` as the last framework-bearing Scriptorium release; - summarize the retained CLI and HTTP application interfaces without duplicating their contracts; - state that all known downstream Go consumers were migrated; - name Promptkit `v0.1.0` as the released binary's framework dependency; and - link to canonical CLI, HTTP, configuration, operations, migration, and Promptkit consumer documents. Use absolute tag URLs for links that must work from the hosted release page. Scriptorium `v0.12.0` tag URLs will not exist before publication; validate their corresponding repository-relative targets locally before tagging and the actual URLs in Stage 5. Promptkit `v0.1.0` links must already resolve. ### Validation - Run every copyable non-destructive migration command against a temporary Go module or a temporary copy of the maintained historical consumer shape. Confirm it selects Promptkit `v0.1.0`, contains no Scriptorium import, and compiles. - Validate every local and currently published cross-project link. - Confirm every prospective Scriptorium `v0.12.0` URL maps to an existing path in the candidate tree. - Run `git diff --check`. - Re-audit for stale project identity, framework ownership, pre-cutover, and planned-release claims. ### Completion State Commit the combined Scriptorium release-workflow, release-procedure, migration, release-note, policy, and navigation changes with one or more plain-English messages. Push them to `origin/main`. Require a clean Scriptorium working tree with `main` synchronized to `origin/main` before Stage 4. Do not tag the release yet. ## Stage 4: Perform The Independent Pre-Release Acceptance Run This is a validation and release-readiness stage. Do not modify product code, move tags, or publish a release while running it. ### Promptkit Main And Published Tag 1. Confirm Promptkit's local `main`, `origin/main`, local annotated `v0.1.0` tag, remote tag object, and resolved tag commit. 2. On Promptkit `main`, run: - `go test ./...`; - `go test -race ./...`; - `go vet ./...`; - `go build ./...`; - `go run ./examples/go-library/prepare`; - `gofmt -l` over tracked Go files; - local and cross-project Markdown-link checks; - `git diff --check`; - module identity, no-workspace, no-replacement, no-vendor, and tracked-tree hygiene checks. 3. Clone the remote Promptkit `v0.1.0` tag into a temporary directory with fresh task-specific `GOMODCACHE` and `GOCACHE` directories and `GOWORK=off`. Run the complete documented Promptkit validation there. 4. From a separate temporary consumer module, resolve `gitea.maximumdirect.net/eric/promptkit@v0.1.0` through the ordinary remote module path and confirm its origin metadata and expected source commit without reading the sibling Promptkit checkout. ### Scriptorium Release Candidate Clone the pushed Scriptorium release commit from `origin/main` into a temporary directory. Use fresh task-specific module and build caches and `GOWORK=off`. Perform all checks from that clone: 1. Confirm: - module path and Go version; - direct Promptkit requirement exactly `v0.1.0`; - module graph selection of Promptkit `v0.1.0`; - no `replace`, `go.work`, `go.work.sum`, vendor tree, root Go package, former framework packages, Promptkit internal import, or sibling path; - `go mod tidy -diff` produces no changes; and - local and remote `v0.12.0` tags do not exist. 2. Run: - `go test ./...`; - `go test -race ./...`; - `go vet ./...`; - `gofmt -l` over tracked Go files; - `git diff --check`; - architecture and tracked-tree hygiene checks; - the maintained render script; - render smoke checks with both configuration examples; and - every maintained local, Promptkit-tagged, and other existing external documentation link. 3. Build a temporary native executable and exercise basic help and offline render behavior. 4. Reproduce the release workflow with `CI_COMMIT_TAG=v0.12.0` into temporary output: - select and copy `docs/releases/v0.12.0.md`; - build stripped, trimmed Linux `amd64` and `arm64` binaries; - verify exact filenames, nonempty files, target operating systems and architectures, and absence of the obsolete linker assignment; - compute SHA-256 checksums in the same basename-only form expected from the plugin; and - confirm no extra file matches the upload glob. 5. Confirm repository-relative targets for the not-yet-live Scriptorium `v0.12.0` release-note links. ### Downstream Confirmation In the Notarius checkout: - require a clean `main` synchronized with `origin/main`; - confirm `go.mod` directly requires Promptkit and no tracked file imports the former Scriptorium Go package; and - run `go test ./...`. If another downstream consumer is discovered, stop and disposition it under the Step 8 gate before publication. ### Release Checkpoint Record the exact Scriptorium release commit, Promptkit tag object and commit, validation commands, and results. Confirm both source repositories remain clean after validation. Any failure returns work to the owning earlier stage. Repeat the complete Stage 4 acceptance run after the fix is committed and pushed. Proceed only when the validated Scriptorium commit is the exact clean `origin/main` commit intended for `v0.12.0`. ## Stage 5: Publish And Verify Scriptorium `v0.12.0` This stage performs external, tag-triggered publication. Do not start it without confirmed repository access, the hosted release secret and workflow, and the complete Stage 4 evidence. ### Tag Publication 1. Fetch `origin/main` and all tags without changing files. 2. Reconfirm that `v0.12.0` is absent locally and remotely and that the working tree is clean at the validated release commit. 3. Create an annotated `v0.12.0` tag. Its message must identify Scriptorium `v0.12.0`, the exact release commit, and that the documented release validation passed. 4. Inspect the tag object and resolved commit. 5. Push only `refs/tags/v0.12.0`. 6. Compare the local and remote annotated tag object IDs and resolved commit IDs. Never move, delete, or recreate a published release tag. A transient hosted workflow failure may be retried against the same tag. A source or workflow defect discovered after tag publication requires a fix on `main` and an explicit roadmap/version decision before a later patch release; do not silently retag `v0.12.0` or mark Step 9 complete. ### Hosted Release Verification 1. Monitor the Woodpecker tag pipeline until it reaches a terminal state. 2. Require both the build and publish steps to succeed. 3. Inspect the Gitea release and require: - a non-prerelease `v0.12.0` release; - release body content sourced from `docs/releases/v0.12.0.md`; - exactly the intended Linux `amd64` binary, Linux `arm64` binary, and `SHA256SUMS` release assets; and - no source-copy, Promptkit binary, release-note file, or stale artifact uploaded by the workflow. 4. Download all three assets into a temporary directory. 5. Verify `SHA256SUMS` against both binaries, confirm file types and target architectures, and inspect that neither file is empty or malformed. 6. Run basic `--help` and offline render smoke behavior on a downloaded binary when the host or an available isolated Linux runtime supports its architecture. When execution is unavailable, record that limitation and rely on the matching pre-release binary smoke plus downloaded-artifact format and checksum verification. 7. Verify every Scriptorium `v0.12.0` and Promptkit `v0.1.0` URL in the hosted release notes. 8. Resolve Scriptorium `v0.12.0` and Promptkit `v0.1.0` through fresh remote Go module queries and confirm their expected tag commits and dependency edge. ### Completion State Retain the publication evidence needed for the final completion record. Remove temporary downloads and confirm no release outputs entered either repository. Do not retire the roadmaps until every hosted verification passes. ## Stage 6: Record Completion And Retire Migration Roadmaps Work in Scriptorium only after Stage 5 is fully complete. ### Completion Record 1. Update `docs/roadmap/migration.md` to mark Step 9 and the overall Promptkit migration complete. 2. Update `docs/roadmap/step9.md` and this implementation plan with a concise completion summary containing: - Promptkit tag and commit; - Scriptorium tag and commit; - hosted release and asset results; - downstream status; - independent validation results; and - any explicitly accepted platform limitation in downloaded-binary execution. 3. Commit and push that completion record with a plain-English message. This commit provides the historical completion snapshot before temporary files are removed. ### Roadmap Retirement In a subsequent commit: 1. Move any still-useful current contract or procedure into its already designated permanent owner. 2. Remove all completed Promptkit-migration roadmaps: - `docs/roadmap/migration.md`; - `docs/roadmap/step7.md`; - `docs/roadmap/step9.md`; and - `docs/roadmap/implementation.md`. 3. Remove the empty `docs/roadmap/` directory if no unrelated active roadmap remains. 4. Search the full repository for incoming links or prose references to the removed files and repair them by linking to ADRs, the release procedure, versioned release notes, migration guide, or another canonical owner. 5. Do not change accepted ADR decision content. Git history, tags, hosted release notes, permanent migration guidance, and the completion-record commit retain the durable history. ### Final Validation Run: - all local Markdown-link checks; - all maintained cross-project links; - `git diff --check`; - a stale-reference search for removed roadmap paths and pre-cutover claims; - tracked-tree hygiene checks in both repositories; and - `git status --short --branch` in Scriptorium, Promptkit, and Notarius. The cleanup is documentation-only and does not require repeating unrelated Go tests unless the cleanup changes a command, example, or behavior-bearing file. Commit and push the retirement with a plain-English message. ## Final Completion State The implementation is complete when: - Promptkit main contains accurate reusable release guidance and still publishes `v0.1.0` as an independently validated source-only Go module; - Scriptorium main contains a canonical release procedure, permanent migration guide, versioned `v0.12.0` release notes, and a release workflow matching the current application; - Scriptorium `v0.12.0` is published from the independently validated commit with verified Linux `amd64` and `arm64` binaries and SHA-256 checksums; - the hosted release body matches the checked-in versioned notes; - Notarius remains migrated and no other downstream Go consumer remains; - neither repository or release depends on local multi-repository state; - both repositories are clean and synchronized with their remotes; and - the completed temporary migration roadmaps have been removed after their completion record was committed. ## Open Questions None. The Step 9 feature roadmap, accepted ADRs, current release topology, and repository policies determine the required implementation and release choices.