Files
scriptorium/docs/roadmap/implementation.md

23 KiB

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 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. 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/<tag>.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.
  • 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/<tag>.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.