Files
narratio/README.md

393 lines
14 KiB
Markdown
Raw Normal View History

2026-05-02 14:13:27 +00:00
# narratio
`narratio` is a Go orchestration application for processing D&D session audio into transcripts and generated artifacts.
## Current Implementation
Implemented now:
2026-05-03 15:23:47 -05:00
- strict config loading/validation (`pipeline.yml` and `session.yml`)
- local workspace/session layout, locking, and manifest persistence
- resumable stage control (`run`, `plan`, `resume`, `run-stage`, `status`)
2026-05-10 21:40:31 +00:00
- real `prepare`, `transcribe`, `merge`, `polish`, `normalize`, `trim`, and `analyze` stages
- real WhisperX, Seriatim, and Audita adapters
- real Scriptorium subprocess adapter
- optional Scriptorium render diagnostics (`render_debug`)
2026-05-03 15:23:47 -05:00
Not implemented yet:
2026-05-03 19:13:50 -05:00
2026-05-10 21:47:21 +00:00
- `notify` stage behavior
- additional analyze artifacts beyond `session_recap`
- generic DAG orchestration
2026-05-03 19:13:50 -05:00
## Config Files
2026-05-04 07:48:59 -05:00
Narratio expects two YAML files:
2026-05-04 07:48:59 -05:00
- `pipeline.yml`: pipeline/workspace settings
- `session.yml`: per-session settings
2026-05-04 07:48:59 -05:00
Pipeline config lookup for CLI commands:
- if `--config <path>` is provided, Narratio uses that path
- if `--config` is omitted, Narratio searches in this order:
- `/usr/local/etc/narratio/pipeline.yml`
- `/etc/narratio/pipeline.yml`
Optional secrets-from-files config:
- `pipeline.secrets.env_dir` may point to a directory of secret files
- each top-level file with an env-var-style name is loaded as an environment variable:
- file name = env var name
- file contents = env var value (trailing newline/CRLF trimmed)
- process environment wins: existing env vars are not overwritten
- if configured, Narratio fails fast when `env_dir` is missing/unreadable
- relative `env_dir` values resolve from Narratio’s current working directory
YAML decoding is strict (`KnownFields(true)`), so unknown fields fail fast.
2026-05-04 07:48:59 -05:00
2026-05-16 14:11:59 +00:00
## Storage And Archive Foundations
2026-05-16 14:33:42 +00:00
Narratio now includes configuration and path-model foundations for archive support, plus implemented prepare-stage S3 audio input.
2026-05-16 14:11:59 +00:00
Implemented foundations:
- `pipeline.storage.s3` config shape (`bucket`, `root_prefix`, `region`, `endpoint`, `force_path_style`)
- `pipeline.spool` config shape (`root`, `delete_audio_after_archive`)
- `pipeline.archive` config shape (`enabled`, `upload_run`, `promote_artifacts`)
- promotion-rule validation (`from`/`to` required, relative-only paths, traversal rejected)
- `session.campaign` requirement for campaign-aware path construction
2026-05-16 14:33:42 +00:00
- optional `session.inputs.audio_s3.prefix` modeling and prepare-stage S3 audio download
2026-05-16 14:11:59 +00:00
- run ID generation and S3/local path helper foundations
- manifest run/path identity fields
Current defaults:
- `pipeline.storage.s3.root_prefix`: `dnd`
- `pipeline.spool.root`: `/var/spool/narratio`
- `pipeline.spool.delete_audio_after_archive`: `false`
- `pipeline.archive.enabled`: `true`
- `pipeline.archive.upload_run`: `true`
- default `pipeline.archive.promote_artifacts`:
- `transcripts/trimmed.json` -> `transcripts/trimmed.json` (`required: true`)
- `artifacts/session_recap.md` -> `artifacts/session_recap.md` (`required: true`)
Current boundaries:
- local development audio (`audio_dir` / `audio_files`) still works
- `audio_dir`/`audio_files` and `audio_s3` are mutually exclusive
2026-05-16 14:22:04 +00:00
- real S3-compatible backend now exists in the storage adapter package
- storage backend tests use fake storage and do not require live S3
- archive uploads successful run records under `runs/{run_id}/`
- archive does not upload local audio by default
- archive does not yet perform promotion writes
2026-05-16 14:11:59 +00:00
- no `current/manifest.json` or `current/run_id.txt` uploads yet
2026-05-16 14:33:42 +00:00
S3 input details and current boundaries are documented in [docs/s3-audio-input.md](docs/s3-audio-input.md).
2026-05-16 14:22:04 +00:00
## Remote Storage Backend
Narratio includes an object-store backend layer for future prepare/archive work:
- `List(ctx, prefix)`
- `Download(ctx, key, localPath)`
- `Upload(ctx, localPath, key, opts)`
- `Exists(ctx, key)`
Implemented backends:
- fake storage backend for deterministic tests
- S3-compatible backend built from `pipeline.storage.s3`
Key invariant:
- callers pass full bucket-relative object keys
- storage backends do not prepend `root_prefix` and do not infer session/campaign paths
Current boundary:
2026-05-16 14:33:42 +00:00
- `prepare` uses `List` + `Download` through the backend when `session.inputs.audio_s3` is configured
- `archive` uses `Upload` through the backend for successful run-record uploads
- promotion uploads and current-pointer writes are still not implemented
Archive run-upload details and boundaries are documented in [docs/archive-storage.md](docs/archive-storage.md).
2026-05-16 14:22:04 +00:00
2026-05-08 17:16:13 +00:00
## Canonical Stage Order
1. `prepare`
2. `transcribe`
3. `merge`
4. `polish`
2026-05-10 21:26:53 +00:00
5. `normalize`
6. `trim`
7. `analyze`
8. `archive`
9. `notify`
2026-05-08 17:16:13 +00:00
## Transcript Tiers
- `transcripts/merged.json`: canonical deterministic merged transcript from Seriatim merge
2026-05-10 21:44:53 +00:00
- `transcripts/processed.json`: full raw Audita-polished transcript output
2026-05-10 21:40:31 +00:00
- `transcripts/normalized.json`: Seriatim-normalized transcript from the normalize stage
2026-05-10 21:44:53 +00:00
- `transcripts/trimmed.json`: gameplay-only normalized polished transcript from trim stage
2026-05-08 17:16:13 +00:00
## Audita Configuration
`pipeline.audita` configures the real Audita subprocess adapter used by `polish`.
Required:
- `binary`
- `timeout`
- `base_url`
- `model`
Optional:
- `llm_api_key_env` (when set, Narratio requires that env var and passes it to Audita as `AUDITA_LLM_API_KEY`)
- `modules` override list (when empty/omitted, Narratio does not pass `--modules`)
- `transcript_description`
- `config_path`
- `output_schema` (`bare-segments` or `audita-v1`)
- `work_dir_retention` (`always`, `auto`, or `never`)
- `total_llm_concurrency` (> 0 when provided)
- `proposal_llm_concurrency` (> 0 when provided)
- `validation_model`
- `validation_llm_concurrency` (> 0 when provided)
- `report` (defaults to `true`)
Narratio passes only configured optional Audita flags. Omitted optional values are left to Audita runtime defaults.
2026-05-10 21:30:35 +00:00
## Normalize Configuration
`pipeline.normalize` is optional. When omitted, Narratio defaults to:
- `output_path: transcripts/normalized.json`
- `output_schema: seriatim-intermediate`
- `report: true`
Allowed `normalize.output_schema` values:
- `seriatim-minimal`
- `seriatim-intermediate`
- `seriatim-full`
`normalize.output_path` is treated as session-workdir-relative when not absolute.
2026-05-10 21:44:53 +00:00
Normalize stage behavior summary:
- normalize runs after `polish` and before `trim`
- normalize resolves `transcripts/processed.json`
- normalize runs Seriatim `normalize` to produce `transcripts/normalized.json`
- normalize diagnostics are written to:
- `artifacts/seriatim.normalize.report.json` (when enabled)
- `logs/seriatim.normalize.stdout.log`
- `logs/seriatim.normalize.stderr.log`
- `config/seriatim.normalize.generated.yml`
2026-05-08 17:16:13 +00:00
## Trim Configuration
2026-05-08 16:54:17 +00:00
`pipeline.trim` is optional. If omitted, no trim config is loaded. If `trim.enabled` is omitted, it defaults to `false`.
When `trim.enabled: true`:
- `trim.output_path` is required
- `trim.bounds.prompt_id` is required
- `trim.bounds.transcript_input_name` is required
- `trim.bounds.output_path` is required
- `trim.bounds.timeout` must be a valid Go duration when provided
- `trim.bounds.render_debug: true` requires `trim.bounds.render_output_path`
- `trim.bounds.profile_id` may be empty to use the prompt default profile
Trim paths are treated as session-workdir-relative when not absolute.
2026-05-08 17:16:13 +00:00
Example trim config:
2026-05-08 16:54:17 +00:00
```yaml
trim:
enabled: true
output_path: "transcripts/trimmed.json"
bounds:
prompt_id: "dnd_session.bounds"
profile_id: ""
transcript_input_name: "transcript"
output_path: "artifacts/session_bounds.json"
timeout: "10m"
render_debug: false
render_output_path: "artifacts/session_bounds.render.json"
seriatim:
report: false
```
2026-05-08 17:16:13 +00:00
Trim behavior summary:
2026-05-10 21:26:53 +00:00
- trim discovers and validates `transcripts/normalized.json`
2026-05-08 17:16:13 +00:00
- trim uses Scriptorium bounds (`dnd_session.bounds` by example config) to produce `artifacts/session_bounds.json`
2026-05-10 21:26:53 +00:00
- bounds IDs are validated against the same normalized transcript ID space that Seriatim trim will consume
2026-05-08 17:16:13 +00:00
- trim converts bounds to Seriatim keep selector (for example `10-868`) and runs Seriatim trim
2026-05-10 21:41:54 +00:00
- if trim is disabled, Narratio copies normalized transcript to trimmed transcript and records `trim_action=copy_disabled`
2026-05-08 17:16:13 +00:00
Trim outputs and diagnostics:
- `artifacts/session_bounds.json`
- `transcripts/trimmed.json`
- `logs/scriptorium.bounds.stdout.log`
- `logs/scriptorium.bounds.stderr.log`
- `config/scriptorium.bounds.generated.yml`
- `logs/seriatim.trim.stdout.log`
- `logs/seriatim.trim.stderr.log`
- `config/seriatim.trim.generated.yml`
- optional bounds render-debug outputs:
- `artifacts/session_bounds.render.json`
- `logs/scriptorium.bounds.render.stdout.log`
- `logs/scriptorium.bounds.render.stderr.log`
- `config/scriptorium.bounds.render.generated.yml`
2026-05-08 17:18:47 +00:00
Render-debug files are diagnostics and are not treated as canonical stage output artifact refs.
## Scriptorium Configuration
2026-05-04 07:48:59 -05:00
`pipeline.scriptorium` is optional. When present, Narratio validates and uses it for analyze-stage artifact generation.
2026-05-04 07:48:59 -05:00
Key points:
2026-05-06 21:12:22 +00:00
- `scriptorium.binary` is required when section is present
- `scriptorium.config_path` is optional
- `scriptorium.timeout` defaults to `10m` when omitted
- `scriptorium.render_debug` enables render diagnostics globally
- artifacts are configured under `scriptorium.artifacts` (map shape supports multiple artifacts)
2026-05-06 21:12:22 +00:00
- enabled artifacts require `prompt_id` and `output_path`
- artifact `render_debug` may override global render setting
- `vars` currently support boolean and string values
Example `session_recap` artifact definition:
```yaml
scriptorium:
binary: "scriptorium"
config_path: "/etc/scriptorium/config.yml"
timeout: "10m"
render_debug: false
artifacts:
session_recap:
enabled: true
prompt_id: "dnd.session_recap"
profile_id: "local-quality" # optional
output_path: "artifacts/session_recap.md"
timeout: "10m"
# render_debug: true # optional per-artifact override
inputs:
transcript:
source: "trimmed_transcript"
required: true
previous_recap:
source: "previous_session_artifact"
artifact: "session_recap"
path: "" # optional; set when available
required: false
vars:
session_id: true
session_date: true
campaign_name: true
previous_session_id: true
output_kind: "session_recap"
```
2026-05-06 21:12:22 +00:00
Prompt IDs and profile IDs are configuration values. They are not hardcoded in analyze-stage logic.
2026-05-06 21:12:22 +00:00
Do not put secrets in `pipeline.yml`. If API-key behavior is configured, use env var names only.
2026-05-06 21:12:22 +00:00
If `pipeline.secrets.env_dir` is configured, keep only references and secret files there; secret values are still not written to manifests, generated configs, or Narratio-managed logs.
## Scriptorium Runtime Behavior
2026-05-03 19:13:50 -05:00
Narratio integrates with Scriptorium through the public CLI subprocess contract:
2026-05-03 19:13:50 -05:00
- generation: `scriptorium run`
- diagnostics/testing: `scriptorium render --format json` when `render_debug` is enabled
For the initial implementation, only `session_recap` generation is supported.
Analyze-stage session recap behavior:
2026-05-02 11:44:15 -05:00
2026-05-10 21:44:53 +00:00
- available transcript input sources for configured artifacts: `processed_transcript`, `normalized_transcript`, `trimmed_transcript`
2026-05-08 17:16:13 +00:00
- session recap should use gameplay-only transcript input (`source: trimmed_transcript`)
- Narratio resolves `trimmed_transcript` from trim manifest output (`transcript_trimmed`) or fallback `transcripts/trimmed.json`
- Narratio resolves `normalized_transcript` from normalize manifest output (`transcript_normalized`) or fallback `transcripts/normalized.json`
2026-05-08 17:16:13 +00:00
- missing trimmed transcript fails clearly and advises running trim stage first
- `normalized_transcript` is the preferred full-transcript source for future table/meta-analysis artifacts
- `processed_transcript` remains supported for advanced/debug use cases
- optionally includes `previous_recap` when configured and resolvable
- omits optional previous recap when unavailable
- fails if required inputs are missing
- validates output file exists and is non-empty
2026-05-02 11:44:15 -05:00
Expected session output paths:
2026-05-02 11:44:15 -05:00
- `artifacts/session_recap.md`
- `logs/scriptorium.session_recap.stdout.log`
- `logs/scriptorium.session_recap.stderr.log`
- `config/scriptorium.session_recap.generated.yml`
- `artifacts/session_recap.render.json` when render diagnostics are enabled
2026-05-02 11:44:15 -05:00
## Examples
2026-05-02 11:44:15 -05:00
Starter files:
2026-05-02 11:44:15 -05:00
- `examples/pipeline.minimal.yml`
- `examples/session.minimal.yml`
- `examples/speakers.yml`
2026-05-02 11:44:15 -05:00
## Commands
2026-05-02 11:44:15 -05:00
Run tests:
```bash
2026-05-02 11:44:15 -05:00
go test ./...
```
Plan a run:
2026-05-02 11:44:15 -05:00
```bash
go run ./cmd/narratio plan --session examples/session.minimal.yml
2026-05-02 11:44:15 -05:00
```
Use `--config <path>` to override default pipeline lookup when needed.
Run full pipeline:
2026-05-03 22:24:27 -05:00
```bash
go run ./cmd/narratio run --config examples/pipeline.minimal.yml --session examples/session.minimal.yml
```
2026-05-04 08:09:58 -05:00
Run analyze only:
```bash
go run ./cmd/narratio run-stage --config examples/pipeline.minimal.yml --session examples/session.minimal.yml analyze
```
2026-05-08 17:16:13 +00:00
## Operational Note
Checksum-based stale detection is not implemented yet.
If prepared inputs or prompt/runtime config change, rerun the appropriate upstream stages before relying on downstream artifacts.
Examples:
2026-05-10 21:26:53 +00:00
- glossary/autocorrect/speaker-context changes: rerun at least `merge`, `polish`, `normalize`, `trim`, and `analyze`
- trim bounds prompt/profile/config changes: rerun at least `normalize`, `trim`, and `analyze`
2026-05-08 17:16:13 +00:00
- session recap prompt/profile/input-source changes: rerun `analyze`
## Roadmap
2026-05-04 08:09:58 -05:00
Near-term roadmap:
2026-05-02 11:44:15 -05:00
- extend analyze to additional configured artifacts
- support workflows where later artifacts consume earlier generated artifacts
- keep orchestration explicit without a generic DAG engine
- implement archive and notify backends