# JSON Output This document is the durable JSON output file-format contract produced by the implemented `json` output module and written by the CLI. ## Output Directory The CLI writes logical output files under: ```text // ``` The default output root is `./notarius-output`. Operational behavior is covered in [Operations](../operations.md). ## Files The `json` output module writes: - `index.json` - `manifest.json` - `artifacts/.json`, one file per approved artifact type - `rejected.json` - `warnings.json` Files are pretty-printed JSON with a trailing newline. ## `index.json` Shape: ```json { "manifest_file": "manifest.json", "artifact_files": [ { "artifact_type": "dnd.spell_cast", "file": "artifacts/dnd.spell_cast.json" } ], "rejected_file": "rejected.json", "warnings_file": "warnings.json" } ``` `artifact_files` is sorted by artifact type. It is empty when no artifacts are approved. ## `manifest.json` `manifest.json` contains a run manifest: ```json { "run_id": "run-123", "pipeline_id": "dnd-session", "pipeline_digest": "sha256:...", "input_module": "seriatim", "chunker": "dnd/scenes", "module_metadata": { "chunker": { "prompt_id": "dnd.scenes", "prompt_version": "v1", "prompt_sha256": "sha256:...", "response_schema_key": "dnd_scenes", "response_schema_id": "notarius.dnd.scenes", "response_schema_name": "notarius_dnd_scenes_v1", "response_schema_version": "v1", "response_schema_sha256": "sha256:..." } }, "source_digests": ["sha256:..."], "extractors": ["dnd/spells"], "merger": "appendorder", "normalizer": "noop", "output_encoder": "json", "artifact_lanes": [ { "id": "spells", "extractor": "dnd/spells", "merger": "appendorder", "normalizer": "noop" } ], "llm_profiles": [ { "id": "default", "provider": "openai-compatible", "model": "configured-model" } ], "validation_status": "approved", "started_at": "2026-01-01T00:00:00Z", "completed_at": "2026-01-01T00:00:01Z" } ``` Fields with empty values may be omitted by JSON encoding. `source_digests` contains source document digests only. Bound references are recorded separately under `references`, which contains provenance only: lane ID, slot name, origin type and URI, digest, media type, byte size, and binding source. Reference content is not written to durable output. When references are bound, the manifest section has this shape: ```json { "references": [ { "lane_id": "events", "slot_name": "roster", "origin_type": "file", "origin_uri": "file:///absolute/path/roster.txt", "digest": "sha256:...", "media_type": "text/plain; charset=utf-8", "size_bytes": 123, "binding_source": "config" } ] } ``` `module_metadata` is omitted when no singleton module provides metadata. `validation_status` is `approved` when no candidates were rejected and `rejected` when one or more candidates were rejected. Top-level `module_metadata` is reserved for singleton pipeline modules (`input`, `chunker`, and `output`). Lane-owned module metadata remains under `artifact_lanes[].metadata`. ## Artifact Files Each artifact file has this shape: ```json { "artifact_type": "dnd.spell_cast", "artifacts": [ { "extractor_key": "dnd/spells", "artifact_type": "dnd.spell_cast", "schema_version": "v1", "payload": {}, "source_refs": [ { "source_id": "session-alpha", "start_unit_id": "seg-001", "end_unit_id": "seg-001" } ] } ] } ``` Artifact envelope fields: - `extractor_key`: extractor module key. - `artifact_type`: artifact type. - `schema_version`: artifact schema version. - `payload`: artifact-type-specific JSON payload. - `source_refs`: optional generic source references. - `metadata`: optional artifact metadata. Artifact file names are produced by sanitizing the artifact type: - characters outside `A-Z`, `a-z`, `0-9`, `.`, `_`, and `-` become `_`; - repeated `..` sequences are replaced; - leading and trailing `.`, `_`, and `-` are trimmed; - empty sanitized names are rejected. For current D&D spell-cast artifacts, the file is `artifacts/dnd.spell_cast.json`. ## `rejected.json` Shape: ```json { "rejected": [ { "candidate": { "index": 0, "extractor_key": "dnd/spells", "artifact_type": "dnd.spell_cast", "schema_version": "v1", "payload": {}, "source_refs": [] }, "validator_name": "dnd/spells/source_refs", "reason_code": "missing_source_ref", "message": "spell cast candidate must include at least one source ref" } ] } ``` `rejected` is an empty array when no candidates are rejected. ## `warnings.json` Shape: ```json { "warnings": [ { "scope": "output", "reason_code": "example_warning", "message": "warning message" } ] } ``` `warnings` is an empty array when no warnings are reported. ## Path Safety The output module returns slash-separated logical paths. The CLI also validates logical output names before writing: - names must be non-empty; - names must be relative; - names must be clean; - names must use `/`, not `\`; - names must not contain `..`; - resolved paths must stay under the run output directory. Durable writes are atomic per file.