18 KiB
Roadmap: Runtime-Defined Scriptorium Artifacts
Status
Proposed implementation roadmap.
Purpose
Narratio currently treats artifact generation as a narrow analyze stage that supports a hard-coded session_recap artifact. This roadmap describes how to generalize artifact generation so operators can define multiple Scriptorium-backed output artifacts at runtime through pipeline.yml.
The goal is to let Narratio continue acting as an orchestrator while making session artifacts configurable, composable, resumable, and visible through a unified artifact model.
Desired Outcome
Operators should be able to define artifacts such as session recaps, player handouts, NPC summaries, quest logs, entity maps, or other campaign-specific outputs without changing Narratio code.
A configured artifact should be declared under pipeline.scriptorium.artifacts.<name> and should define, at minimum:
- whether it is enabled;
- which Scriptorium prompt to run;
- where the output should be written;
- which Narratio artifacts should be passed as Scriptorium inputs;
- which static vars should be passed to Scriptorium.
Configured artifacts should become canonical runtime artifact IDs using this form:
narratio.artifact.<artifact_name>
For example, an artifact declared as:
scriptorium:
artifacts:
session_recap:
enabled: true
prompt_id: dnd_session.session_recap
output_path: artifacts/session_recap.md
should be registered as:
narratio.artifact.session_recap
Other configured artifacts should then be able to use it as an input:
scriptorium:
artifacts:
player_handout:
enabled: true
depends_on:
- session_recap
prompt_id: dnd_session.player_handout
output_path: artifacts/player_handout.md
inputs:
recap:
source: narratio.artifact.session_recap
required: true
Scope
This roadmap covers:
- introducing a runtime artifact catalog;
- generalizing configured Scriptorium artifact execution;
- supporting
narratio.artifact.<name>source IDs; - adding explicit artifact dependencies;
- recording dynamic artifacts in stage metadata and the session manifest;
- preserving compatibility for the existing
session_recapbehavior; - updating tests and documentation.
Non-Goals
This roadmap does not attempt to turn Narratio into a general workflow engine.
Specifically, this feature should not add:
- arbitrary shell-command artifacts;
- multi-stage user-defined workflows;
- conditional branching;
- loops;
- remote artifact discovery beyond existing archive/session behavior;
- semantic understanding of each configured artifact type.
Narratio should continue to orchestrate a fixed pipeline. The configurable part is the set of Scriptorium artifact invocations performed during the analyze stage.
Current State
Narratio already has several relevant pieces in place:
pipeline.scriptorium.artifactsis modeled as a map of artifact definitions.- The Scriptorium adapter already accepts generic run/render requests.
- The artifact resolver already understands canonical artifact source IDs.
- The
analyzestage already resolves inputs, optionally runs render-debug, invokes Scriptorium, verifies output, and records metadata.
The main limitation is that analyze currently treats session_recap as the only executable artifact and rejects other enabled artifact definitions.
Target Architecture
Runtime Artifact Catalog
Introduce a per-run artifact catalog that tracks both built-in and configured artifacts.
The catalog should include:
- Built-in artifacts produced by fixed pipeline stages.
- Configured Scriptorium artifacts declared under
pipeline.scriptorium.artifacts. - Availability/provenance state for artifacts that have been produced or resolved from the manifest.
Conceptually:
ArtifactCatalog
├── built-in artifacts
│ ├── narratio.transcript.merged
│ ├── narratio.transcript.polished
│ ├── narratio.transcript.full
│ ├── narratio.transcript.trimmed
│ └── narratio.bounds.session
│
└── configured artifacts
├── narratio.artifact.session_recap
├── narratio.artifact.player_handout
└── narratio.artifact.npc_summary
The catalog should distinguish between planned and available artifacts:
- A planned artifact is validly declared and may be produced during the current run.
- An available artifact has been produced successfully in the current run or resolved from prior successful manifest state.
Artifact Source IDs
Configured artifact keys should map directly to canonical source IDs:
pipeline.scriptorium.artifacts.<name>
→ narratio.artifact.<name>
Example:
pipeline.scriptorium.artifacts.session_recap
→ narratio.artifact.session_recap
The existing hard-coded narratio.artifact.session_recap source should become a normal configured-artifact source, while retaining compatibility behavior where needed.
Configured Artifact Dependencies
Add optional depends_on support to configured artifacts.
Example:
scriptorium:
artifacts:
session_recap:
enabled: true
prompt_id: dnd_session.session_recap
output_path: artifacts/session_recap.md
inputs:
transcript:
source: narratio.transcript.trimmed
required: true
player_handout:
enabled: true
depends_on:
- session_recap
prompt_id: dnd_session.player_handout
output_path: artifacts/player_handout.md
inputs:
recap:
source: narratio.artifact.session_recap
required: true
depends_on values should refer to configured artifact keys, not full source IDs.
Use topological sorting to determine execution order. Fail validation on:
- dependency references to missing or disabled artifacts;
- self-dependencies;
- dependency cycles.
If two artifacts are independent, execute them in deterministic sorted-name order.
Input Resolution
Input resolution should use the artifact catalog and existing artifact resolver behavior.
For each configured artifact input:
- built-in sources should resolve through the existing resolver;
previous_session_artifactshould preserve existing behavior;narratio.artifact.<name>should resolve only if the named configured artifact is available;- optional missing inputs should be omitted;
- required missing inputs should fail the artifact run.
Runtime-configured artifacts should not be considered available merely because their output path exists on disk. They should be available only when:
- they were produced successfully earlier in the current
analyzeexecution; or - they are recorded as successful outputs in prior manifest state being used for resume; or
- Narratio intentionally supports a documented canonical fallback for that artifact.
For the initial implementation, prefer options 1 and 2 only.
Analyze Stage Generalization
The analyze stage should become the generic Scriptorium artifact stage.
Its high-level flow should be:
- Load configured Scriptorium artifacts.
- Filter to enabled artifacts.
- If no artifacts are enabled, return success metadata with
skipped=true. - Build the runtime artifact catalog.
- Validate configured artifact names, source IDs, paths, dependencies, and required fields.
- Sort enabled artifacts by dependency order.
- For each artifact:
- resolve configured inputs;
- build the Scriptorium run request;
- optionally run Scriptorium render-debug;
- run Scriptorium;
- fail on validation-failed result;
- verify the output exists and is non-empty;
- record artifact metadata;
- register
narratio.artifact.<name>as available in the catalog.
- Return aggregate stage metadata containing all generated artifacts.
The Scriptorium adapter should remain generic. It should not decide which artifacts run, how dependencies work, or how artifacts are registered.
Manifest and Metadata
The analyze stage should record all generated configured artifacts in manifest/stage metadata.
Recommended metadata shape:
{
"skipped": false,
"artifacts": [
{
"name": "session_recap",
"source_id": "narratio.artifact.session_recap",
"output_kind": "scriptorium_artifact",
"path": "artifacts/session_recap.md",
"prompt_id": "dnd_session.session_recap",
"profile_id": "local-gemma-31b",
"provenance": "manifest.analyze.outputs"
},
{
"name": "player_handout",
"source_id": "narratio.artifact.player_handout",
"output_kind": "scriptorium_artifact",
"path": "artifacts/player_handout.md",
"prompt_id": "dnd_session.player_handout",
"profile_id": "local-gemma-31b",
"provenance": "manifest.analyze.outputs"
}
]
}
For backward compatibility, session_recap may continue to emit any legacy output kind or metadata expected by existing tests and archive behavior.
Resume Behavior
The initial implementation can keep stage-level resume behavior.
That means:
- if
analyzehas already succeeded and is not forced, the runner can skip it as before; - if
analyzeis forced, all enabled configured artifacts should be regenerated; - if one artifact fails, the stage fails;
- a later rerun can re-execute the analyze stage as a whole.
Per-artifact resume can be considered later, but it is not necessary for the first version.
Archive Behavior
Do not automatically archive every generated artifact.
Artifact generation and archive promotion should remain separate concerns. Operators should continue to use archive.promote_artifacts to decide which generated files should be promoted or uploaded.
Example:
archive:
promote_artifacts:
- from: artifacts/session_recap.md
to: artifacts/session_recap.md
required: true
- from: artifacts/player_handout.md
to: artifacts/player_handout.md
required: false
A later enhancement may add opt-in automatic promotion of generated artifacts, but explicit promotion should remain the default.
Implementation Plan
Phase 1: Config Model and Validation
Add or update the configured artifact model to include:
enabled;depends_on;prompt_id;profile_id;output_path;timeout;render_debug;inputs;vars.
Validation rules:
- artifact names must match a conservative identifier pattern such as
^[a-z][a-z0-9_]*$; - enabled artifacts require
prompt_idandoutput_path; - enabled artifact output paths must be run-relative and must not escape the run workspace;
- dependency references must point to enabled configured artifacts;
- dependencies must not contain cycles;
narratio.artifact.<name>input sources must refer to known configured artifacts;- input names and var names must remain compatible with the Scriptorium adapter's validation rules;
- disabled artifacts should not be executable or dependency targets.
Tests:
- valid single configured artifact;
- valid multiple independent artifacts;
- valid artifact-to-artifact dependency;
- invalid artifact name;
- missing required fields;
- dependency on missing artifact;
- dependency on disabled artifact;
- cycle detection;
- typo in
narratio.artifact.<name>source; - unknown YAML fields still fail strict decode.
Phase 2: Runtime Artifact Catalog
Introduce an internal artifact catalog abstraction.
Responsibilities:
- register built-in artifact definitions;
- register configured artifact definitions;
- map configured artifact keys to
narratio.artifact.<name>IDs; - track planned versus available artifacts;
- expose lookup by canonical source ID;
- record provenance when an artifact becomes available.
Keep the catalog narrow. It should not execute anything and should not know about Scriptorium prompts.
Tests:
- built-in source lookup;
- configured source registration;
- duplicate/conflicting source handling;
- planned but unavailable artifact lookup;
- registering an artifact as available after generation;
- resolving a configured artifact from prior manifest metadata.
Phase 3: Resolver Integration
Update artifact resolution so configured artifact IDs are resolved through the runtime catalog.
Resolution behavior:
- built-in sources continue using existing manifest-preferred, canonical-fallback behavior;
- configured artifact sources resolve from catalog availability/provenance;
- missing optional configured artifact inputs are omitted;
- missing required configured artifact inputs fail clearly.
Tests:
- configured artifact consumes a built-in transcript source;
- configured artifact consumes another configured artifact produced earlier in the same analyze run;
- configured artifact consumes another configured artifact from prior manifest state;
- required missing configured artifact fails;
- optional missing configured artifact is omitted.
Phase 4: Analyze Stage Generalization
Refactor analyze to execute all enabled configured artifacts.
Implementation notes:
- preserve the existing skip behavior when Scriptorium config is absent or no artifacts are enabled;
- remove the hard-coded rejection of non-
session_recapartifacts; - compute deterministic dependency order before execution;
- execute artifacts one at a time in dependency order;
- keep render-debug behavior at global and artifact levels;
- keep Scriptorium adapter invocation logic generic;
- after each successful run, register the artifact as available in the catalog;
- aggregate metadata across all artifacts.
Tests:
- no Scriptorium config skips;
- empty artifact map skips;
- disabled artifacts do not run;
- one enabled artifact runs;
- multiple independent artifacts run in deterministic order;
- dependent artifact receives prior artifact as input;
- render-debug works for configured artifacts;
- Scriptorium validation failure fails the stage;
- missing required input fails the stage;
- successful outputs are non-empty and recorded.
Phase 5: Manifest Compatibility and Output Kinds
Update manifest/stage output recording to support dynamic configured artifacts.
Recommended behavior:
- every configured artifact gets
source_id: narratio.artifact.<name>; - every configured artifact gets a generic output kind such as
scriptorium_artifact; session_recapmay also retain legacy metadata/output kind for compatibility;- manifest provenance should be sufficient for later resolution during resume.
Tests:
- manifest records one configured artifact;
- manifest records multiple configured artifacts;
session_recapremains compatible with existing expectations;- configured artifact can be resolved from manifest metadata on later run/resume.
Phase 6: Documentation and Examples
Update documentation after the implementation is complete.
Recommended documentation changes:
- update
docs/config.mdwith the generalized artifact configuration model; - update
docs/internal/artifacts.mdto describe the runtime artifact catalog; - update
docs/stages/analyze.mdto describe generic Scriptorium artifact generation; - update Scriptorium integration docs only if the adapter contract changes;
- update full annotated pipeline examples;
- add at least one example with multiple artifacts and one dependency.
Documentation should make clear that:
- configured artifact source IDs use
narratio.artifact.<name>; depends_onuses artifact keys, not full source IDs;- archive promotion remains explicit;
- per-artifact resume is not part of the initial implementation.
Migration Strategy
Existing configurations using session_recap should continue working.
Recommended migration path:
- Treat
pipeline.scriptorium.artifacts.session_recapas a normal configured artifact. - Keep
narratio.artifact.session_recapas a supported source ID. - Preserve existing default archive promotion for
artifacts/session_recap.mdwhere applicable. - Preserve existing tests for session recap behavior while adding new generic artifact tests.
- Remove or update documentation that says only
session_recapis supported.
Open Decisions
Before implementation, decide the following:
- Should configured artifact output paths be required to live under
artifacts/? - Should disabled artifacts be valid references for
narratio.artifact.<name>sources, or should validation fail immediately? - Should
depends_onbe required whenever an artifact input references another configured artifact, or should Narratio infer dependencies from input source IDs? - Should the first implementation support configured artifact resolution from prior manifest state, or only from artifacts produced earlier in the same analyze execution?
- Should
session_recapkeep a legacy output kind forever, or only through a compatibility window?
Recommended answers:
- Prefer requiring configured artifact outputs under
artifacts/unless there is a strong reason not to. - Fail references to disabled artifacts.
- Require
depends_onfor clarity, and validate that it matches artifact input references. - Support prior manifest resolution if the existing manifest model makes this straightforward; otherwise defer.
- Keep legacy
session_recapcompatibility until the next major release boundary.
Acceptance Criteria
The feature should be considered complete when:
- operators can define more than one enabled Scriptorium artifact in
pipeline.yml; - Narratio runs all enabled artifacts in deterministic dependency order;
- configured artifacts are addressable as
narratio.artifact.<name>; - one configured artifact can consume another configured artifact as an input;
- missing required inputs fail clearly;
- optional missing inputs are omitted;
- render-debug behavior works for all configured artifacts;
- generated artifacts are recorded in manifest/stage metadata;
- existing
session_recapbehavior remains compatible; - archive promotion remains explicit;
- tests cover config validation, dependency sorting, resolver behavior, analyze execution, and manifest metadata.