24 KiB
Promptkit Migration Roadmap
Status: Completed roadmap record.
Purpose
This roadmap records the scope, decisions, and completed outcome of replacing
the external Scriptorium CLI integration with Promptkit. Canonical
documentation outside docs/roadmap/ owns the implemented behavior.
Pre-Migration Baseline
Status: Historical migration input.
Before the migration, Weatherreporter exposed seven report definitions, but only four had complete prompt-backed report implementations:
- Daily Report:
weather.daily_generated_text - Today Report:
weather.today_generated_text - Tomorrow Report:
weather.tomorrow_generated_text - Hourly Report:
weather.hourly_generated_text
The three-day, weekend, and storm commands and registry definitions had no
corresponding Scriptorium prompt or schema and never formed complete
operational report products. The weather.daily_report Scriptorium prompt was
legacy source material and was not selected by the registry.
The Scriptorium source corpus was retained temporarily under
docs/roadmap/scriptorium/ as migration input. It contained the four
operational generated-text prompt definitions, their referenced content,
private response schemas, shared instructions, and the unused legacy Daily
Markdown prompt. The temporary corpus was removed after the runtime assets
were reconciled and embedded.
Implemented End State
Status: Completed.
Weatherreporter pins
gitea.maximumdirect.net/eric/promptkit at v0.4.0 and uses it as the
in-process engine for prompt inspection, prepared execution, provider calls,
and first-pass output validation.
The scriptorium executable, subprocess adapter, configuration, runtime
dependency, direct-Markdown execution path, and integration documentation have
been removed. The four operational reports continue to use structured
generated text followed by weatherreporter-owned validation and Markdown
templates.
The unfinished three-day, weekend, and storm reports are not implemented as part of this migration. Their incomplete CLI, registry, documentation, and generation declarations are removed from the implemented surface before the migration is considered complete. Any future implementation of those products requires separate roadmap scope, prompt and schema design, tests, and documentation.
Weather selection, forecast derivation, valid periods, module construction, Recent Changes, generated-text interpretation, Markdown templates, durable state, inspection, output copies, and Distributor notification remain owned by weatherreporter.
The four report prompts and private response schemas are versioned embedded application assets. Operators configure Promptkit profiles without replacing the report-owned corpus. One Promptkit engine is constructed per CLI invocation and shared by every report in that invocation, including all reports in a morning or evening batch.
Promptkit is isolated behind a weatherreporter-owned execution contract. Promptkit request, result, validation, error, profile, backend, and provider types do not leak into application orchestration, report definitions, domain packages, CLI summaries, durable state contracts, or Distributor behavior.
Goals
Status: Completed migration outcomes.
- Removed the Scriptorium runtime dependency and subprocess boundary.
- Migrated the four operational report prompts to Promptkit
v0.4.0. - Used prepared execution to persist preparation provenance before provider work while executing the exact frozen snapshot.
- Validated report prompt and profile selections before weather collection when the required information is available.
- Preserved deterministic module snapshots and structured Recent Changes.
- Preserved generated-text domain validation and repository-owned Markdown rendering.
- Preserved context cancellation, actionable errors, secret redaction, and inspectable failures.
- Improved durable prompt provenance with prompt, input, profile, model, validation, usage, and timing metadata.
- Kept content-rich prompt and response diagnostics separate from routine metadata and CLI output.
- Kept tests offline and deterministic through injected Promptkit model clients and fixtures.
- Removed incomplete report declarations from the implemented product surface rather than creating new report products during an integration migration.
Non-Goals
Status: Completed migration constraints.
The completed migration did not:
- create prompts, schemas, templates, or completed products for three-day, weekend, or storm reports;
- preserve the unused
weather.daily_reportlegacy Markdown prompt as an active runtime asset; - preserve a direct-Markdown LLM generation mode;
- move meteorological selection, derivation, thresholds, or comparison logic into prompts or Promptkit;
- send raw unbounded Weather API responses to the model;
- replace weatherreporter's generated-text domain validation or Markdown template rendering;
- add a general workflow engine, provider plugin system, or arbitrary backend registry;
- add automatic provider, validation, repair, or capacity retries;
- add concurrent report generation to the sequential batch workflow;
- expose Promptkit types as weatherreporter contracts;
- keep a production-selectable Scriptorium/Promptkit dual-run mode;
- require Promptkit eager source validation, structured generation errors, or semantic execution-target fingerprints; or
- use an unpublished Promptkit commit, committed Go workspace, or committed local module replacement.
Locked Decisions
Status: Implemented migration decisions.
Dependency And Upgrade Boundary
- The migration pins the tagged Promptkit
v0.4.0release. - Coordinated local development may temporarily use the sibling Promptkit checkout, but committed module metadata must reference the tagged release.
- The adapter relies on the public root Promptkit package only.
- A future Promptkit upgrade requires explicit review of prepared-execution lifecycle, prompt and profile inspection, prompt/profile/schema formats, error identities, validation behavior, capacity behavior, and the outbound provider contract.
- Promptkit's deferred eager source validation, structured generation errors, and semantic execution-target fingerprints do not block this migration.
Operational Report Scope
- The migration preserves these prompt IDs:
weather.daily_generated_text,weather.today_generated_text,weather.tomorrow_generated_text, andweather.hourly_generated_text. - Each operational report definition selects the exact embedded prompt version
1.0.0; execution does not rely on ambiguous single-version lookup. - Morning and evening batch membership remains based on Today, Tomorrow, and eligible future Daily reports.
- Three-day, weekend, and storm are removed from current CLI help, parsing, report registry membership, tests that claim implemented generation, and non-roadmap documentation.
- The future product concepts may remain under
docs/roadmap/, but migration verification does not invent outputs or compare nonexistent prompts.
Application Boundary
- Promptkit remains an adapter boundary even though it runs in process.
- A weatherreporter-owned contract represents prompt identity, preparation, execution, output, validation, usage, provenance, and neutral error categories.
- The Promptkit adapter maps public Promptkit values into that contract.
- App orchestration and test fakes depend on the project-owned contract, not Promptkit.
- Scriptorium-specific request, result, error, and generation-mode types are removed rather than renamed and retained.
Prompt And Schema Ownership
- Weatherreporter embeds the four operational prompt definitions, referenced prompt content, shared prompt content, and private response schemas.
- Assets remain separate files rather than inline Go strings.
- The temporary corpus under
docs/roadmap/scriptorium/is migration source material, not the final runtime location. - Weatherreporter's existing generated-text domain types, schemas, and templates remain the canonical application contract. Imported Scriptorium assets are reconciled with that contract rather than copied blindly or kept as duplicate runtime schemas.
- The imported Daily schema's incorrect Today
$idand title are corrected. confidenceis handled consistently across each prompt, provider-facing schema, generated-text domain type, and template. The existing optional weatherreporter field remains supported unless a separate domain decision removes it.- Prompt input metadata identifies the serialized data package as YAML rather than JSON.
- Imported
pipeline-weather/...schema paths are replaced with paths valid inside the embedded Promptkit schema source. - Imported
repair_attempts: 2values are removed or set to zero. The migration does not rely on Promptkit's internal-only repair capability. - The unused
weather.daily_reportprompt is not promoted into runtime assets. - One centralized embedded prompt/schema source is sufficient; Weatherreporter does not need Notarius's multi-module asset-flattening registry.
Profiles, Backends, And Credentials
- Execution profiles remain operator-configurable rather than embedded report policy.
- Each embedded operational prompt declares Promptkit's built-in
gemini-flash-latestprofile as its default. gemini-flash-latestis intentionally a moving model alias. The execution record captures the effective model identity, but operators who require a pinned model must select an explicit external profile.- Configuration supports at most one external profile source:
promptkit.profile_fileorpromptkit.profile_dir. The two fields are mutually exclusive. - A nonblank
promptkit.profileis the explicit request profile for every report in the invocation and takes precedence over each prompt'sdefault_profile. A blank value uses the prompt default. - Promptkit's normal profile-source precedence remains intact: an external matching profile takes precedence over an embedded built-in profile, and an invalid matching external profile is an error rather than a reason to fall back.
- Weatherreporter exposes Promptkit's conventional
localbackend through the narrowpromptkit.local.endpointandpromptkit.local.concurrency_limitconfiguration fields. It does not expose arbitrary backend registration. - A configured local endpoint registers the engine-scoped
localbackend. An operator-supplied external profile selects it withbackend: localand owns the model-specific settings; Weatherreporter does not invent a local model profile. - Local concurrency defaults to one. A value of zero means unlimited, matching Promptkit, and a negative value is invalid. Queue capacity and general backend parameters are not exposed.
- Credential values remain in environment variables or file-backed environment secrets. Configuration contains only credential source names.
- Provider credentials never appear in logs, errors, CLI output, durable metadata, preparation records, execution records, or debug summaries.
- Promptkit
InspectProfilereports structural target and credential requirements; Weatherreporter owns policy for checking configured environment availability. - Promptkit revalidates environment credentials at
RunPrepared; a successful preparation does not promise that execution-time credentials remain available.
Configuration Contract
The replacement configuration surface is:
promptkit:
profile: ""
profile_file: ""
profile_dir: ""
timeout: 2m
local:
endpoint: ""
concurrency_limit: 1
timeoutremains the transport-wide provider-call safety cap.- A blank local endpoint leaves the conventional local backend unregistered.
- Scriptorium's
binary,config_path, andextra_argssettings have no Promptkit equivalents and are removed. - Configuration validation rejects simultaneous
profile_fileandprofile_dirvalues, invalid local endpoints, negative concurrency, and selected profiles that cannot resolve their backend.
Engine Construction And Inspection
- One Promptkit engine is constructed per CLI invocation at the application composition boundary.
- Single-report generation and every report in a batch use that same engine.
- Per-report orchestration does not construct a default engine.
- Promptkit backend capacity state and HTTP transport are shared consistently for the invocation.
- Before collection,
InspectPromptchecks every selected report's exact ID and version, declareddata_packageinput, default-profile metadata, prompt hash availability, and declared output contract. InspectPromptis a point-in-time structural check. It does not load a JSON Schema, resolve a profile, or freeze later execution.- Explicit profile overrides and relevant prompt defaults are checked with
InspectProfilebefore collection when application policy requires them. InspectProfileis also point-in-time and does not check credential values.- Successful
PrepareExecution, not inspection, is the per-run authority for loaded schema, rendered content, frozen inputs, effective settings, and durable execution provenance.
Prompt Input
- Promptkit receives only the curated
data_packageproduced byinternal/promptinput. - Weatherreporter serializes the package once, atomically persists those exact bytes, and supplies the same bytes with a Promptkit inline artifact.
- The managed data-package path may be supplied as non-secret provenance through the inline artifact URI.
- Weatherreporter does not delegate unrestricted path loading to Promptkit's default file artifact reader.
- Prompt inspection and adapter tests verify that
data_packageis required and declared with the chosen YAML media type.
Prepared Execution
Engine.PrepareExecutionreplaces Scriptorium render preflight.- Weatherreporter obtains
PreparedExecution.Details, maps a safe subset into its own preparation record, and persists that record before callingEngine.RunPrepared. RunPreparedexecutes the frozen prompt, profile, schema, inputs, rendered messages, target, and validation resources retained by the handle.- Every acquired handle is followed immediately by
defer handle.Discard(). Discard is safe after execution and releases unused private execution state. - Handles remain adapter-local, engine-bound, one-shot, in-process values. They are never serialized, persisted, copied into app contracts, or treated as restartable jobs.
- Preparation and execution use independent contexts. Execution receives the active report workflow context.
- Capacity is not reserved during preparation. Capacity rejection can therefore occur after a preparation record has been persisted.
RunPreparedconsumes the handle on success and every operational failure.- Preparation details remain available from the adapter after execution or discard, but rendered messages are not copied into routine durable state.
- Promptkit execution timing excludes preparation and consumer-held delay. Weatherreporter records preparation timing and execution timing separately.
Execution And Validation
- All four operational reports use Promptkit JSON Schema output validation.
- A completed Promptkit validation rejection returns a
RunResult; the adapter retains raw output and bounded validation details before failing the report. - An operational generation or validation error returns no partial
RunResult. - Weatherreporter's
internal/generatedtextvalidation remains the final report-specific decode and domain boundary. - Weatherreporter's
internal/reporttemplateremains responsible for managed Markdown rendering. - Weatherreporter atomically persists Promptkit raw output and later artifacts rather than asking Promptkit to choose managed filesystem paths.
- No Promptkit output-repair behavior is assumed or requested.
Durable Artifacts And Observability
Status: Implemented design constraints.
Routine durable state retains useful non-secret provenance without persisting full rendered prompts.
The preparation record contains:
- prompt ID and exact version;
- prompt definition hash;
- rendered prompt hash;
- input hashes;
- selected profile and backend identity;
- effective model identity;
- output contract summary;
- preparation start, end, and duration; and
- the path of the exact persisted data package.
The execution record and run metadata contain, when available:
- Promptkit run ID;
- prompt ID, version, and hashes;
- input hashes;
- selected profile, backend, and model identity;
- generated-content hash;
- token usage;
- execution start, end, and duration;
- validation status and bounded diagnostics; and
- paths of separately persisted raw output, normalized generated text, render context, managed Markdown, and other artifacts reached by the workflow.
Provider endpoints, full effective model parameter maps, rendered messages, schema bodies, data-package contents, and generated content do not belong in routine metadata or CLI summaries.
Rendered messages and other content-rich preparation or response diagnostics
are available only when the operator supplies
--llm-debug-dir <path> to a single-report or batch command.
- There is no persistent YAML setting for debug capture.
- The debug root is validated or created before weather collection or provider work. A requested destination that cannot be secured or written is an error.
- Artifacts are grouped beneath
<path>/<report-id>/<valid-date>/<run-id>/. - Directories and files use owner-only permissions and atomic writes.
- Debug artifacts may contain rendered messages and content-rich preparation or response diagnostics, but never credentials.
- The debug path appears in command output only when debug capture is enabled; it is not added to routine durable metadata.
- Debug artifacts are not cache or comparison inputs. Their retention is owned by the operator who selected the directory.
Artifact Identities And Versions
Weatherreporter replaces Scriptorium-specific artifact identities rather than reusing names whose meanings have changed:
PromptPreparationArtifactuses schema versionweatherreporter.prompt_preparation.v1, is written asprompt_preparation.<runID>.json, and is referenced bypreparationPath.PromptExecutionArtifactuses schema versionweatherreporter.prompt_execution.v1, is written asprompt_execution.<runID>.json, and is referenced byexecutionPath.- Run metadata advances to
weatherreporter.metadata.v2and uses those new path fields.
Preparation files remain beneath the existing configurable preflight/
directory, and execution files remain beneath the existing snapshots/ tree.
The stable physical grouping limits deployment disruption without preserving
misleading Scriptorium-era filenames or field names. Raw generated output,
normalized generated text, render context, managed Markdown, and other
artifacts whose meanings have not changed retain their existing names and
locations.
Run inspection remains able to read weatherreporter.metadata.v1 and its
legacy preflightPath and generatedTextResultPath references. New runs write
only the v2 metadata and new artifact names; Weatherreporter does not
dual-write deprecated aliases. CLI summary fields adopt preparationPath and
executionPath as an explicit, documented contract change.
Failure Contract
Status: Implemented design constraints.
- A preparation failure produces a redacted weatherreporter-owned failure receipt with report, RunID, prompt, stage, timing, and classified error context. It does not fabricate Promptkit preparation details.
- An operational execution failure retains the successful preparation record and adds a redacted execution failure receipt. No partial Promptkit result or model output is invented.
- A Promptkit validation rejection retains the returned result, raw generated output, validation details, and safe provenance before the report fails.
- A later generated-text decode, domain-validation, or template failure retains every raw and validated artifact reached before that stage.
- Caller cancellation takes precedence when the active workflow context is canceled.
promptkit.CapacityErroris recognized witherrors.As; its backend ID is copied into a weatherreporter-owned capacity error whileErrCapacityExceededremains the classification.- Capacity rejection is an operational report failure, not invalid model output, and does not trigger an automatic retry.
- Other Promptkit public error identities are translated into the narrow weatherreporter error categories needed by CLI, metadata, and batch behavior. Diagnostic prose is not parsed as a contract.
- Single-report commands return the classified failure with available inspectable paths.
- Batch runs continue independent later reports under the existing batch failure policy.
- Any future retry policy belongs to app orchestration, not the adapter.
Compatibility Requirements
Status: Implemented design constraints.
- Daily, Today, Tomorrow, and Hourly report IDs, prompt IDs, valid periods, artifact grouping, output names, and Distributor bundle behavior remain stable.
- Morning and evening batch collection, planning, ordering, and continuation behavior remains stable.
- Module snapshot and Recent Changes behavior remains deterministic.
- Promptkit receives only the existing curated prompt-input boundary.
- Managed Markdown remains the Distributor upload source.
- RunID lookup and inspection remain available for successful and failed runs.
- Existing managed paths remain stable where their meaning is unchanged. Scriptorium-specific artifact names or schemas change when retaining them would misrepresent the Promptkit contract.
- Existing v1 run metadata and referenced artifacts remain inspectable after the migration. New runs use the v2 metadata and Promptkit-era artifact identities without dual-writing deprecated aliases.
- Artifact or metadata schema changes are explicit, documented, and covered by state and inspection tests.
- Prompt or generated content is not added to routine logs or CLI summaries.
- Tests do not require live providers or credentials.
- Removing incomplete three-day, weekend, and storm surfaces is documented as correction of an unfinished product boundary, not as successful Promptkit migration of those reports.
Verification And Completion Criteria
Status: Completed and verified.
Completion was verified by the following outcomes:
- the four operational reports inspect, prepare, and execute through Promptkit
v0.4.0using embedded report-owned assets; - every report uses exact prompt version
1.0.0, requires the YAMLdata_package, and declares the expected JSON Schema output contract; - prepared execution persists a safe preparation record before provider work and executes the same frozen snapshot;
- deterministic offline adapter and app tests cover success, preparation failure, credential revalidation, capacity rejection, cancellation, timeout, generation failure, Promptkit validation rejection, generated-text domain failure, template failure, and handle discard;
- morning and evening batches construct one engine and preserve current collection, planning, ordering, continuation, output, and notification behavior;
- the temporary corpus has been reconciled into one runtime prompt/schema source without duplicate provider-facing schemas;
- configuration examples load and contain no Scriptorium fields;
- CLI summaries and inspection commands expose the new project-owned artifact contract without Promptkit types;
- Scriptorium code, configuration, tests, and runtime documentation have been removed;
- incomplete three-day, weekend, and storm commands, registry entries, tests, and current-behavior documentation have been removed or moved to roadmap scope;
- non-roadmap documentation describes only the implemented Promptkit integration;
go test ./..., required focused or race-enabled checks, CLI help validation, andgit diff --checkpass; and- no committed
go.work, localreplace, live-provider test, or secret-bearing fixture remains.
Fixture-based comparison with prior Scriptorium behavior is sufficient. Production dual-run is not required because model calls are nondeterministic, costly, and difficult to compare meaningfully.
Decision Status
Status: Completed.
The roadmap has no remaining open product or architecture questions. Later changes to this completed scope require new roadmap or decision-record scope rather than implicit changes to this historical record.