# 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": "generic", "module_metadata": { "chunker": { "prompt_id": "dnd.scenes", "prompt_version": "v1", "prompt_sha256": "sha256:...", "response_schema_key": "dnd_scenes", "response_schema_id": "schema-dnd-scenes", "response_schema_name": "dnd_scenes", "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. `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.