# Machine-Readable JSON Schemas
## English
### Purpose
- Each file in this directory is a JSON Schema Draft 2020-12 document
- Output schemas describe the exact stdout contract of every `sqlite-graphrag` subcommand
- Input schemas describe the accepted JSON payloads for file-driven graph ingestion
- Agents and parsers MUST validate responses against these schemas before processing
- Most schemas use `"additionalProperties": false` — unexpected keys are contract violations
- `health.schema.json` (v1.0.89, GAP-E2E-007, ADR-0048) uses `"additionalProperties": true` (Must-Ignore policy per RFC 7493 I-JSON and `rules_rust_json_e_ndjson.md:33`) — unknown keys are accepted to enable schema evolution
- The 17 new fields added in v1.0.89: `vec_memories_missing`, `vec_memories_orphaned`, `sqlite_version`, `mentions_ratio`, `mentions_warning`, `top_relation`, `top_relation_ratio`, `applies_to_ratio`, `relation_concentration_warning`, `super_hub_count`, `super_hub_warning`, `top_hub_entity`, `top_hub_degree`, `hub_warning`, `non_normalized_count`, `normalization_warning`, `fts_query_ok`
- New exit code 16 (`EX_CONFIG`) emitted by `AppError::PreFlightFailed` is documented in v1.0.87 (ADR-0045, GAP-META-005) — see `error-envelope.schema.json` for the structured `PreFlightError` variant details
### Schema Files
> **Cross-cutting schema.** `agent-surface.schema.json` is not bound to a single subcommand. It defines `$defs/AgentSurfaceMeta` and `$defs/CountOnlyEnvelope`, referenced by every envelope that accepts the agent-native flags (`--select`, `--filter`, `--max-items`, `--sort`, `--dedupe-by`, `--count-only`, `--truncate-content`, `--max-output-bytes`). Since v1.2.5 (GAP-SG-191) it also carries `secondary_capped`, the list of secondary array keys `--max-items` truncated.
| Subcommand | Schema file |
|---|---|
| `init` | `init.schema.json` |
| `remember` (updated v1.0.84, ADR-0042) | `remember.schema.json` |
| `recall` (updated v1.0.84, ADR-0042 / v1.0.85, ADR-0043 enum 7 variants) | `recall.schema.json` |
| `read` | `read.schema.json` |
| `list` | `list.schema.json` |
| `forget` | `forget.schema.json` |
| `purge` | `purge.schema.json` |
| `rename` | `rename.schema.json` |
| `edit` (updated v1.0.84, ADR-0042) | `edit.schema.json` |
| `history` | `history.schema.json` |
| `restore` | `restore.schema.json` |
| `hybrid-search` (updated v1.0.84, ADR-0042 / v1.0.85, ADR-0043 enum 7 variants) | `hybrid-search.schema.json` |
| `deep-research` | `deep-research.schema.json` |
| `deep-research --output` (v1.1.05) | `deep-research-output-ack.schema.json` |
| `health` | `health.schema.json` |
| `migrate` | `migrate.schema.json` |
| `migrate --rehash` (v1.0.76, updated v1.0.77, v1.0.78) | `migrate-rehash.schema.json` |
| `migrate --to-llm-only` (v1.0.76, updated v1.0.77, v1.0.78) | `migrate-to-llm-only.schema.json` |
| `namespace-detect` | `namespace-detect.schema.json` |
| `optimize` | `optimize.schema.json` |
| `stats` | `stats.schema.json` |
| `sync-safe-copy` | `sync-safe-copy.schema.json` |
| `vacuum` | `vacuum.schema.json` |
| `link` | `link.schema.json` |
| `unlink` | `unlink.schema.json` |
| `related` | `related.schema.json` |
| `graph` | `graph.schema.json` |
| `graph traverse` | `graph-traverse.schema.json` |
| `graph stats` | `graph-stats.schema.json` |
| `graph entities` | `graph-entities.schema.json` |
| `graph entity-types` (v1.2.8) | `graph-entity-types.schema.json` |
| `graph recompute-degree` (v1.1.01, P3) | `graph-recompute-degree.schema.json` |
| `cleanup-orphans` | `cleanup-orphans.schema.json` |
| `prune-relations` | `prune-relations.schema.json` |
| `reclassify-relation` | `reclassify-relation.schema.json` |
| `split-body` (v1.1.03, GAP-V8) | `split-body.schema.json` |
| `entity_connect_seen` (v1.1.04, GAP-002) | implicit via migration V016 — records `(source_id, target_id, namespace, verdict, relation, evaluated_at)` |
| `normalize-entities` | `normalize-entities.schema.json` |
| `enrich` (phase event) | `enrich-phase.schema.json` |
| `enrich` (per-item event) | `enrich-item-event.schema.json` |
| `enrich` (summary, updated v1.0.84, ADR-0042) | `enrich-summary.schema.json` |
| `enrich --status` (v1.0.96, GAP-ENRICH-BACKLOG-CONVERGE) | `enrich-status.schema.json` |
| `config list` / `config list --effective` | `config-list.schema.json` |
| `ingest` (per-file event) | `ingest-file-event.schema.json` |
| `ingest` (summary, updated v1.0.84, ADR-0042) | `ingest-summary.schema.json` |
| (retired mode, phase event — file retained) | `ingest-claude-phase.schema.json` |
| (retired mode, per-file event — DEPRECATED alias) | `ingest-claude-file-event.schema.json` |
| (retired mode, summary — DEPRECATED alias) | `ingest-claude-summary.schema.json` |
| `debug-schema` | `debug-schema.schema.json` |
| `fts rebuild` | `fts-rebuild.schema.json` |
| `fts check` | `fts-check.schema.json` |
| `fts stats` | `fts-stats.schema.json` |
| `backup` | `backup.schema.json` |
| `delete-entity` | `delete-entity.schema.json` |
| `reclassify` | `reclassify.schema.json` |
| `merge-entities` | `merge-entities.schema.json` |
| `rename-entity` | `rename-entity.schema.json` |
| `memory-entities` (forward: `--name`) | `memory-entities.schema.json` |
| `memory-entities` (reverse: `--entity`) | `memory-entities-reverse.schema.json` |
| `prune-ner` | `prune-ner.schema.json` |
| `remember-batch` (per-item event) | `remember-batch.schema.json` |
| `remember-batch` (summary) | `remember-batch-summary.schema.json` |
| `export` (per-memory line) | `export-memory-line.schema.json` |
| `export` (summary) | `export-summary.schema.json` |
| `vec orphan-list` (v1.0.69) | `vec-orphan-list.schema.json` |
| `vec purge-orphan` (v1.0.69) | `vec-purge-orphan.schema.json` |
| `vec stats` (v1.0.69) | `vec-stats.schema.json` |
| `slots status` (v1.0.82, GAP-004) | `slots-status.schema.json` |
| `embedding status` (v1.0.82, GAP-005, updated v1.0.84, ADR-0042) | `embedding-status.schema.json` |
| `embedding list` (v1.0.82, GAP-005) | `embedding-list.schema.json` |
| shutdown envelope (v1.0.82, GAP-002) | `shutdown-envelope.schema.json` |
| error envelope (all commands) | `error-envelope.schema.json` |
### Commands Without JSON Schemas
- `completions` emits shell completion scripts (Bash, Zsh, Fish, PowerShell, Elvish) as plain text — no JSON schema applies
- `help` / `--help` is CLI meta (plain text) — no JSON schema applies
- `cache` (`list` / `stats` / `clear-models`) has **no** dedicated `cache.schema.json`; JSON output is informal / operational (list + size stats). Agents should treat unexpected fields as Must-Ignore. Coverage of cache behaviour lives in monographs (`HOW_TO_USE`, `COOKBOOK`, `AGENTS`), not in this schema index
- `daemon` was removed in v1.0.76 (remaining code deleted in v1.0.79) — no JSON schema applies (historical)
### Ingest Mode Schema Selection
- `ingest --mode` accepts **only `none`** (body-only). The LLM-curated modes (`claude-code`, `codex`, `opencode`) were REMOVED; clap rejects them with exit 2, as it already did for `gliner` (removed in v1.1.02)
- `--mode none` uses `ingest-file-event.schema.json` and `ingest-summary.schema.json`
- `ingest-claude-phase.schema.json`, `ingest-claude-file-event.schema.json` and `ingest-claude-summary.schema.json` are **retained artifacts of the retired LLM modes**. Nothing in the CLI emits them any more; they stay in this directory only for consumers pinned to their `$id`. New consumers MUST validate against the canonical `ingest-file-event.schema.json` / `ingest-summary.schema.json`
- Fields the surviving mode does not produce are **omitted from the line**, never emitted as `null`. `entities`, `rels`, `cost_usd`, `input_tokens`, `output_tokens`, `input_tokens_total` and `output_tokens_total` belonged to the retired LLM modes and no longer appear
- Known outlier: the dry-run path emits `status: "skip"` where every other site says `"skipped"`. The canonical schema accepts both and documents `skip` as a legacy alias; consumers MUST treat them as one value
### Error Envelope Changes in v1.0.68 (G28-B)
- The `error-envelope.schema.json` `message` field for `code: 75` now has two distinct templates, both routed to the same exit code
- Template A (new since v1.0.68, G28-B): `job <job_type> for namespace '<namespace>' is already running (exit 75); wait for it to finish or pass --wait-job-singleton <SECONDS>` — emitted by `enrich` when a concurrent invocation holds the singleton
- Template B (legacy): `all <max> concurrency slots occupied after waiting <waited_secs>s (exit 75); use --max-concurrency or wait for other invocations to finish` — emitted by the counting semaphore for any other command
- Agents can disambiguate the two with a regex on `message`: matches `^job ` for Template A and `^all ` for Template B
- The schema itself remains `additionalProperties: false` because variant-specific fields are intentionally NOT serialised to JSON; structured access to `job_type` and `namespace` requires agents to parse the quoted strings inside `message`
### Schema Changes in v1.0.84 (ADR-0042 / GAP-002)
- Seven response schemas gained an OPTIONAL `backend_invoked: enum [claude, codex, opencode, openrouter, none, auto]` field that reports which LLM backend the live embedding path actually invoked (opencode added in v1.0.90)
- Affected envelopes: `embedding-status`, `remember`, `edit`, `recall`, `hybrid-search`, `ingest-summary`, `enrich-summary`
- The field is omitted (not `null`) when no backend was invoked, keeping happy-path envelopes clean
- Agents SHOULD treat `backend_invoked` as the ground truth for which CLI binary ran during the call
### Update (v1.0.85 / ADR-0043)
- Two response schemas gained `vec_degraded_reason` with the seven-variant enum `embedding_failed | slot_exhausted | oauth_quota | backend_mismatch | dim_zero | cancelled | timeout` plus explicit `null` for happy-path. Callers can switch on this discriminator instead of regex against `vec_error` strings.
- Two response schemas also gained `vec_degraded_reason: enum [embedding_failed, cancelled, timeout, null]` for callers that need to distinguish OAuth quota exhaustion from cancellation from timeout
- Affected envelopes: `recall`, `hybrid-search`
- The field is omitted when live embedding succeeded, and explicitly `null` when no degradation path was triggered
- All seven updated schemas keep `"additionalProperties": false`; the new fields are additive and `null`/`omitted` are distinct contract states
- See `docs/decisions/adr-0042-claude-backend-split.md` (EN) and `.pt-BR.md` for the full rationale
### Schema Changes in v1.0.85 (ADR-0043 / five-gap remediation)
- `recall` and `hybrid-search` response schemas extended `vec_degraded_reason` enum from 3 to 7 variants: `embedding_failed | slot_exhausted | oauth_quota | backend_mismatch | dim_zero | cancelled | timeout`
- `slot_exhausted` (GAP-003) discriminates LLM subprocess semaphore contention from quota exhaustion; callers can retry with the global `--wait-lock` flag or the XDG key `llm.slot_wait_secs`
- `oauth_quota` (G58, G45-CR5) discriminates Anthropic usage limit exhaustion from structural embedding errors; triggers deterministic codex <-> claude backend swap before falling back to FTS5
- `backend_mismatch` discriminates requested vs resolved backend divergence (e.g. `--llm-backend claude` resolved to codex via PATH-probe)
- `dim_zero` discriminates an embedding that returned a zero-dimension vector (structural bug indicator distinct from quota or contention)
- The expanded enum is backwards compatible: existing callers that switch on `embedding_failed | cancelled | timeout` continue to work; new variants are additive
- Default embedding `dim` is 64 (MRL, arXiv 2205.13147) since v1.0.79; v1.0.85 confirms and locks the constant at `src/constants.rs:22 DEFAULT_EMBEDDING_DIM = 64` (G56 docs)
- `anthropic-ratelimit-*-remaining` headers are now first-class signal in `LlmEmbedding::invoke_claude` (G45-CR5); a zero value aborts the spawn with `AppError::Embedding` mapped to `FallbackReason::OAuthQuota`
- `read` `AppError::MemoryNotFound` / `MemoryNotFoundById` Display is bilingue via `pt::memory_not_found` / `pt::memory_not_found_by_id` (G55 docs, preserved from v1.0.80)
- All schemas keep `"additionalProperties": false`; the seven-variant enum is the canonical discriminator for live-embedding degradation
- See `docs/decisions/adr-0043-five-gap-remediation.md` (EN) and `.pt-BR.md` for the full rationale
### Mudancas de Schema em v1.0.85 (ADR-0043 / remediacao dos cinco gaps)
- Schemas de resposta `recall` e `hybrid-search` estenderam o enum `vec_degraded_reason` de 3 para 7 variantes: `embedding_failed | slot_exhausted | oauth_quota | backend_mismatch | dim_zero | cancelled | timeout`
- `slot_exhausted` (GAP-003) discrimina contencao do semaforo de subprocessos LLM de exaustao de cota; chamadores podem re-tentar com a flag global `--wait-lock` ou a chave XDG `llm.slot_wait_secs`
- `oauth_quota` (G58, G45-CR5) discrimina exaustao de cota Anthropic de erros estruturais de embedding; dispara troca deterministica codex <-> claude antes de cair em FTS5-puro
- `backend_mismatch` discrimina divergencia entre backend solicitado e resolvido (ex. `--llm-backend claude` resolvido para codex via PATH-probe)
- `dim_zero` discrimina embedding que retornou vetor de dimensao zero (indicador de bug estrutural distinto de cota ou contencao)
- O enum expandido e retrocompativel: chamadores existentes que chaveiam em `embedding_failed | cancelled | timeout` continuam funcionando; variantes novas sao aditivas
- `dim` default de embedding e 64 (MRL, arXiv 2205.13147) desde v1.0.79; v1.0.85 confirma e tranca a constante em `src/constants.rs:22 DEFAULT_EMBEDDING_DIM = 64` (G56 docs)
- Headers `anthropic-ratelimit-*-remaining` agora sao sinal de primeira classe em `LlmEmbedding::invoke_claude` (G45-CR5); valor zero aborta o spawn com `AppError::Embedding` mapeado para `FallbackReason::OAuthQuota`
- `read` `AppError::MemoryNotFound` / `MemoryNotFoundById` Display e bilingue via `pt::memory_not_found` / `pt::memory_not_found_by_id` (G55 docs, preservado desde v1.0.80)
- Todos os schemas mantem `"additionalProperties": false`; o enum de sete variantes e o discriminador canonico para degradacao de embedding live
- Veja `docs/decisions/adr-0043-five-gap-remediation.md` (EN) e `.pt-BR.md` para a justificativa completa
### Input and Cross-Cutting Contracts
These are indexed as a separate table because they are not command-to-envelope
mappings: three describe what a command READS, one describes a preview envelope,
and one is referenced by every envelope that accepts the agent-native flags.
| Contract | Schema |
| --- | --- |
| `remember --entities-file` (input array) | `entities-input.schema.json` |
| `remember --relationships-file` (input array) | `relationships-input.schema.json` |
| `remember --graph-stdin` / `--graph-file` (input document) | `graph-input.schema.json` |
| `remember --dry-run` (preview envelope) | `remember-dry-run.schema.json` |
| agent-native surface (`$defs`, referenced by every envelope) | `agent-surface.schema.json` |
### Usage
- Inspect a `recall` response shape quickly: `sqlite-graphrag recall "query" | jaq '.'`
- Validate with a real JSON Schema validator: `python3 -m jsonschema --instance <(sqlite-graphrag stats) docs/schemas/stats.schema.json`
- The `debug-schema` subcommand is hidden and intended for diagnostic tooling only — the binary exposes it with a double-underscore prefix (`debug-schema`) while the schema file uses the kebab-case name `debug-schema.schema.json` following the directory convention
### Schema Evolution in v1.0.86 → v1.0.89 (ADR-0045, ADR-0046, ADR-0047, ADR-0048, ADR-0049)
- v1.0.86 added 6 schemas for new LLM-pipeline subcommands: `slots-status.schema.json`, `pending-list.schema.json`, `embedding-status.schema.json` (updated v1.0.84 ADR-0042), `embedding-list.schema.json`, `shutdown-envelope.schema.json` (exit 19 envelope). `pending-list.schema.json` was REMOVED in v1.2.8 with the `pending` family; the claim that `pending-embeddings process` reused it was wrong on both halves, since that subcommand never shipped either — the live family is `pending-embeddings list|status|abandon`
- v1.0.87 added `AppError::PreFlightFailed` (exit 16 `EX_CONFIG`) documented in `error-envelope.schema.json` with 8 variants: `ArgvExceedsArgMax`, `BinaryNotFound`, `McpConfigInlineJsonRejected`, `McpConfigPathMissing`, `McpConfigPathInvalidJson`, `WalkUpMcpJsonInvalid`, `OutputBufferTooSmall`, `ClaudeConfigDirNotEmpty`
- v1.0.88 fixed: `oauth_stderr_emits_single_line_v1088` regression test validates exit-19 envelope now emits 1 stderr line (was 2). All other schemas unchanged
- v1.0.89 (GAP-E2E-007) regenerated `health.schema.json` via `schemars 0.8` derive macro. Switched from `additionalProperties: false` to `true` (Must-Ignore). 17 new fields added. New `src/bin/dump_schema.rs` regenerates the schema idempotently via `schema_for!()` + BTreeMap ordering + recursive `apply_must_ignore` policy enforcement
- v1.0.89 (GAP-E2E-008, GAP-E2E-010) added `--db <PATH>` flag parity on 5 subcommands: `embedding-status`, `embedding-list`, `pending-list`, `codex-models`. No schema changes (the flag affects input parsing, not output envelope)
- v1.0.89 (GAP-E2E-009) added `--dry-run` and `--confirm` flags to `migrate`. New `migrate-dry-run.schema.json` describes the structured dry-run report (pending_migrations[], pending_count, checksum_mismatches[], status)
- v1.0.89 (GAP-E2E-011) added `--auto-describe` (default true) to `ingest`. No schema changes; affects how `description` field is populated in `ingest-file-event.schema.json` and `ingest-summary.schema.json` envelopes
### Schema Changes in v1.0.93 (ADR-0052 / OpenRouter Embedding Backend)
- Seven response schemas updated `backend_invoked` enum to include `openrouter` as a sixth variant: `claude | codex | opencode | openrouter | none | auto`
- `openrouter` is emitted when embedding was computed via the OpenRouter REST API (`--embedding-backend openrouter`) instead of a headless LLM subprocess
- Affected envelopes: `embedding-status`, `remember`, `edit`, `recall`, `hybrid-search`, `ingest-summary`, `enrich-summary`
- No new schema files were added — the OpenRouter backend uses the same output envelope structure as existing backends
- `ingest-summary.schema.json` now reflects the `--enrich-after` flag behavior: when active, the summary includes the enrich phase results inline
### Schema Changes in v1.0.95 (ADR-0054 / OpenRouter Chat Enrich)
- `enrich` gains a fourth extraction mode `openrouter` (`--mode openrouter`) that routes the JUDGE turn to the OpenRouter `/chat/completions` REST endpoint instead of a headless `claude`/`codex`/`opencode` subprocess
- NO new schema files were added — `enrich-phase.schema.json`, `enrich-item-event.schema.json`, and `enrich-summary.schema.json` are unchanged; the SCAN→JUDGE→PERSIST envelopes keep the same shape regardless of JUDGE transport
- The optional `backend_invoked` enum already covers `openrouter` (added v1.0.93 for embedding); the same variant now also describes an enrich JUDGE served via OpenRouter chat
- Structured Outputs (`response_format` `json_schema` `strict: true`) make the JUDGE output conform to the same entity/relationship structs the subprocess backends emit — no schema divergence
### Schema Changes in v1.1.04 (ADR-0064)
- Migration V016 introduces the `entity_connect_seen` table recording the LLM verdict (`related`/`none`) per evaluated entity pair for convergent `entity-connect`
- `CURRENT_SCHEMA_VERSION` advances 15 to 16
- The `entity_connect` enrich operation is promoted from scan-only to fully-implemented
- No new output schema file: `entity_connect_seen` is an internal table (implicit schema via the V016 migration), not a subcommand stdout contract
### Schema Changes in v1.1.8 (enrich quality / latency / contract)
- **No required main-DB migration.** `CURRENT_SCHEMA_VERSION` stays at **16**. Enrich sidecar may gain optional `priority` column via idempotent ALTER.
- `remember.schema.json` — additive optional fields `entities_created` (string[]) and `enrich_recommended` (string[]) for hot-set orchestration after write (GAP-CLI-PRIO-01). Pair with CLI flag `remember --enqueue-enrich`.
- `memory-entities.schema.json` — forward items require `description` (string; empty when unset) for parity with reverse lookup (GAP-CLI-ME-01).
- `enrich-status.schema.json` — additive quality/status fields: `scan_backlog_empty`, `scan_backlog_low_quality`, `force_redescribe`, `quality_pct`, `quality_sample_n`, `scan_backlog_low_grounding_est`; `state` includes `blocked_dead` (QISO / CAPA3).
- `enrich-summary.schema.json` — additive optional `budget_exhausted`, `pairs_remaining_estimate`, `yields`, `preempted_for_gate` (EC scale + cooperative preempt).
- `deep-research` short flag `-o` is a CLI alias of `--output`; ack schema unchanged (`deep-research-output-ack.schema.json`).
- Offline gate: `scripts/e2e_offline_v120.sh` (**20/20**). Help must not advertise product `SQLITE_GRAPHRAG_*` env as config.
### Schema Notes in v1.2.2 (`schema` subcommand — no schema field change)
- **No required main-DB migration.** `CURRENT_SCHEMA_VERSION` stays at **16**. Crate **1.2.2**.
- **New `schema` subcommand** — the catalog of all **74** contracts no longer requires an agent to list `docs/schemas/` off disk:
- `sqlite-graphrag schema` emits **NDJSON**, one line per contract, shaped `{"id","invoke"}`; `invoke` is the ready-to-copy command
- `sqlite-graphrag schema --name <ID>` emits that contract's JSON Schema document
- An unknown `<ID>` exits **4** (not found), never an empty catalog
- `--json` does not change the listing: it is NDJSON by definition
- **`$schema` documents are exempt from the agent-native surface.** `--filter`, `--select` and the other v1.2.2 knobs never reshape a contract document; it is recognised by its `$schema` member and passes through untouched. An agent can therefore chain `schema --name <ID>` with any global flag without corrupting the contract.
- **`--mode claude-code` NDJSON contract unified (GAP-SG-148 item 5).** The mode no longer reports through a parallel type: per-file events and the summary use the **same `IngestFileEvent` / `IngestSummary`** as the standard pipeline.
- Per-file `status` is **`indexed`** when a memory was written — **not `done`**. Full enum: `indexed`, `failed`, `skipped`, `preview`
- The summary reports **`files_total`, `files_succeeded`, `files_failed`, `files_skipped`** — **not `completed`**
- `entities`, `rels` and `cost_usd` are optional members of the shared type: they carry values in the LLM modes and are omitted on the wire by the standard pipeline, so a `--mode none` line stays byte-identical to what it was before the unification
### Schema Notes in v1.2.1 (enrich CAPA — no schema field change)
- **No required main-DB migration.** `CURRENT_SCHEMA_VERSION` stays at **16**. Crate **1.2.2** (v1.2.1 note retained below; the agent-native output surface adds no schema field).
- **Sidecar behaviour only** — full CAPA list (no new stdout fields):
1. `dequeue_next_pending` — claim by `operation` **and** `namespace`
2. `count_eligible_pending` for `--until-empty` — counts **op+ns only**
3. `reopen_force_redescribe_candidates` — reopens `skipped`/`done` once per process; **never** `dead`
4. `reconcile_satisfied_reembed_pending` — marks ReEmbed pending `done` when live BLOB matches (`LENGTH(embedding) = dim*4`); clears zombies without API calls
5. Re-embed eligibility by BLOB **LENGTH**, not `dim` column alone (CORRUPT rows re-embed)
6. `entity:` prefix strip on enqueue lookup (queue key stays `entity:…`)
7. Chunk enqueue validates namespace (non-deleted memory in target ns)
8. CAPA-D — compound "configuration file" markers only
- **`enrich-status.schema.json` / `enrich-summary.schema.json` unchanged** — no schema field change expected for the CAPA seal; agents continue Must-Ignore on unknown keys.
- Offline gate remains `scripts/e2e_offline_v120.sh` (**20/20** PASS).
- Regressions: `enqueue_candidate_accepts_entity_prefixed_reembed_key`, `dequeue_next_pending_isolates_by_namespace`; queue suite **38** OK.
### Schema Notes in v1.2.0 (product seal — no new schema files required)
- **No required main-DB migration.** `CURRENT_SCHEMA_VERSION` stays at **16**. Crate **1.2.0**.
- **`DEFAULT_EMBEDDING_DIM=1024`** — `init` stamps `schema_meta.dim` from the default (or `--embedding-dim` / XDG override). Existing DBs keep their stamped dim until re-embed. This is a runtime/init constant change, **not** a new `*.schema.json` file.
- **`enrich --list-skipped` / `enrich --requeue-skipped`** — recoverable skipped/preservation sink (mirrors `--list-dead` / `--requeue-dead`). **No new schema file**: list/requeue reuse the existing dead-inspector envelope (`DeadItem` lines + `DeadSummary` with `action: "list-skipped"` / `"requeue-skipped"`). If a payload looks enrich-status-like or carries extra observational fields, agents **MUST** treat unknown keys as Must-Ignore (do not hard-fail).
- **GAP-SG-139 is a CLI input contract only** (no schema change): host/XDG leaves (`config`, `slots`, `cache`, `completions`) accept `--db` as a documented **no-op** so agents that append `--db` everywhere do not get clap exit 2. Graph subcommands still open the DB.
- Index already covers `config-list.schema.json` for `config list` / `config list --effective`. There is **no** `cache.schema.json` (see Commands Without JSON Schemas).
- Offline gate remains `scripts/e2e_offline_v120.sh` (**20/20** PASS).
### Schema Changes in v1.1.06 (ADR-0066)
- **No required database migration.** `CURRENT_SCHEMA_VERSION` stays at **16**. Operators do **not** need `migrate` for this release.
- Closes **GAP-ENTITY-CONNECT-SCAN-CARTESIAN**: `enrich --operation entity-connect` / `cross-domain-bridges` no longer use a cartesian pair scan. Queue `item_key` is `pair:{id1}:{id2}` with `item_type=entity_pair` (sidecar queue contract; not a main-DB migration). Drain resolves by entity primary key.
- NDJSON phases for operators/hooks: `scan_start` **before** SQL (`operation`, `entities_in_namespace`, `backlog_degree0_proxy`) and `scan_meta` (`pairs_enqueued_this_scan`, `scan_elapsed_ms`). Existing `enrich-phase.schema.json` / `enrich-item-event.schema.json` remain the phase envelopes; field additions are additive observational payloads on those phases.
- First-scan wall-clock uses `InterruptHandle` → Timeout exit **1** (not singleton **75**). No new stdout summary schema file.
- Regression suite: `tests/v1106_entity_connect_scan_regression.rs`. Decision: [ADR-0066](../decisions/adr-0066-v1-1-06-entity-connect-scan.md).
### Schema Changes in v1.1.05 (ADR-0065)
- **No required database migration.** `CURRENT_SCHEMA_VERSION` stays at **16**. Operators do **not** need `migrate` for this release.
- `deep-research` — `sub_queries[].source` now also emits `aspect` (single-token facet fan-out) and `manual` (`--sub-query-strategy manual --sub-queries-file PATH`). `deep-research.schema.json` enum is updated in v1.1.05 to `original | decomposed | aspect | manual`. No new *required* output fields on the full envelope.
- `deep-research --output PATH` — when set, stdout is a short **ack** after atomwrite (tempfile same dir → fsync → rename); the full research envelope is on disk. Dedicated schema: `deep-research-output-ack.schema.json` (Bug 2 / ADR-0065). Required fields: `written` (string path), `bytes` (u64 file size), `blake3` (hex digest of written bytes), `sub_queries_total` (usize), `unique_memories_found` (usize), `elapsed_ms` (u64). `additionalProperties: false`. Regression suite: `tests/v1105_incident_bugs_regression.rs`.
- `link --from-id` / `--to-id` — **CLI input flags only**. The `link.schema.json` **output** envelope is unchanged (`from`/`to` remain entity **names** after resolution). Digit-only strings are rejected as names (`validate_entity_name`); that is validation behaviour, not a new JSON property. Schema description notes the ID flags.
- `graph traverse --fuzzy` — resolution UX: with `--fuzzy`, the `from` field in `graph-traverse.schema.json` is the **resolved canonical name** (may differ from the CLI `--from` argument). NotFound name suggestions remain error UX only.
- Global `--quiet` / `-q` — affects stderr tracing volume only; no stdout schema impact.
### Schema Changes in v1.0.96 → v1.0.97 (ADR-0055, GAP-SG-15/16/41/43)
- v1.0.96 (ADR-0055): `enrich-status.schema.json` for the read-only `enrich --status` report (`unbound_backlog`, per-operation `scan_backlog` (GAP-SG-77, v1.1.0), queue `pending`/`done`/`failed`/`dead`/`skipped`, `eligible_now`, `waiting`); the `.enrich-queue.sqlite` sidecar gains the `error_class`/`next_retry_at` columns and the `dead` terminal status via an idempotent `ALTER TABLE`
- v1.0.97 (GAP-SG-15/16): `enrich-summary.schema.json` gains the `dead` and `waiting` count fields so the summary distinguishes terminal failures and cooldown from an empty backlog
- v1.0.97 (GAP-SG-43): `stats.schema.json` gains a top-level `total_memories` integer
- v1.0.97 (GAP-SG-41): `embedding-status.schema.json` gains a REQUIRED `coverage` object (`memories_total`/`memories_with_vec`/`entities_total`/`entities_with_vec`/`chunks_total`/`chunks_with_vec`) reporting real persisted-vector counts, distinct from the always-empty async `counts` queue; the live `embedding status` output always carries it
- NO main-database schema migration: the SQLite schema stays at v15 across both releases. The v1.0.97 queue-sidecar path change (ADR-0057) is a path-derivation fix, not a schema change
### Input Payload Schemas (Reference)
### Contratos de Entrada e Transversais
Indexados em tabela própria porque não são mapeamentos de comando para envelope:
três descrevem o que um comando LÊ, um descreve o envelope de prévia, e um é
referenciado por todo envelope que aceita as flags agent-native.
| Contrato | Schema |
| --- | --- |
| `remember --entities-file` (array de entrada) | `entities-input.schema.json` |
| `remember --relationships-file` (array de entrada) | `relationships-input.schema.json` |
| `remember --graph-stdin` / `--graph-file` (documento de entrada) | `graph-input.schema.json` |
| `remember --dry-run` (envelope de prévia) | `remember-dry-run.schema.json` |
| superfície agent-native (`$defs`, referenciada por todo envelope) | `agent-surface.schema.json` |
### Usage
- Inspect a `recall` response shape quickly: `sqlite-graphrag recall "query" | jaq '.'`
- Validate with a real JSON Schema validator: `python3 -m jsonschema --instance <(sqlite-graphrag stats) docs/schemas/stats.schema.json`
- The `debug-schema` subcommand is hidden and intended for diagnostic tooling only — the binary exposes it with a double-underscore prefix (`debug-schema`) while the schema file uses the kebab-case name `debug-schema.schema.json` following the directory convention
## Português Brasileiro
### Propósito
- Cada arquivo neste diretório é um documento JSON Schema Draft 2020-12
- Schemas de saída descrevem o contrato exato de stdout de cada subcomando `sqlite-graphrag`
- Schemas de entrada descrevem os payloads JSON aceitos para ingestão de grafo orientada a arquivo
- Agentes e parsers DEVEM validar respostas contra estes schemas antes de processar
- A maioria dos schemas usa `"additionalProperties": false` — chaves inesperadas são violações de contrato
- `health.schema.json` (v1.0.89, GAP-E2E-007, ADR-0048) usa `"additionalProperties": true` (política Must-Ignore por RFC 7493 I-JSON e `rules_rust_json_e_ndjson.md:33`) — chaves desconhecidas são aceitas para permitir evolução do schema
- Os 17 novos campos adicionados em v1.0.89: `vec_memories_missing`, `vec_memories_orphaned`, `sqlite_version`, `mentions_ratio`, `mentions_warning`, `top_relation`, `top_relation_ratio`, `applies_to_ratio`, `relation_concentration_warning`, `super_hub_count`, `super_hub_warning`, `top_hub_entity`, `top_hub_degree`, `hub_warning`, `non_normalized_count`, `normalization_warning`, `fts_query_ok`
- Novo exit code 16 (`EX_CONFIG`) emitido por `AppError::PreFlightFailed` é documentado em v1.0.87 (ADR-0045, GAP-META-005) — veja `error-envelope.schema.json` para detalhes estruturados da variante `PreFlightError`
### Arquivos de Schema
| Subcomando | Arquivo de schema |
|---|---|
| `init` | `init.schema.json` |
| `remember` (atualizado v1.0.84, ADR-0042) | `remember.schema.json` |
| `recall` (atualizado v1.0.84, ADR-0042 / v1.0.85, ADR-0043 enum 7 variantes) | `recall.schema.json` |
| `read` | `read.schema.json` |
| `list` | `list.schema.json` |
| `forget` | `forget.schema.json` |
| `purge` | `purge.schema.json` |
| `rename` | `rename.schema.json` |
| `edit` (atualizado v1.0.84, ADR-0042) | `edit.schema.json` |
| `history` | `history.schema.json` |
| `restore` | `restore.schema.json` |
| `hybrid-search` (atualizado v1.0.84, ADR-0042 / v1.0.85, ADR-0043 enum 7 variantes) | `hybrid-search.schema.json` |
| `deep-research` | `deep-research.schema.json` |
| `deep-research --output` (v1.1.05) | `deep-research-output-ack.schema.json` |
| `health` | `health.schema.json` |
| `migrate` | `migrate.schema.json` |
| `migrate --rehash` (v1.0.76, atualizado v1.0.77, v1.0.78) | `migrate-rehash.schema.json` |
| `migrate --to-llm-only` (v1.0.76, atualizado v1.0.77, v1.0.78) | `migrate-to-llm-only.schema.json` |
| `namespace-detect` | `namespace-detect.schema.json` |
| `optimize` | `optimize.schema.json` |
| `stats` | `stats.schema.json` |
| `sync-safe-copy` | `sync-safe-copy.schema.json` |
| `vacuum` | `vacuum.schema.json` |
| `link` | `link.schema.json` |
| `unlink` | `unlink.schema.json` |
| `related` | `related.schema.json` |
| `graph` | `graph.schema.json` |
| `graph traverse` | `graph-traverse.schema.json` |
| `graph stats` | `graph-stats.schema.json` |
| `graph entities` | `graph-entities.schema.json` |
| `graph entity-types` (v1.2.8) | `graph-entity-types.schema.json` |
| `graph recompute-degree` (v1.1.01, P3) | `graph-recompute-degree.schema.json` |
| `cleanup-orphans` | `cleanup-orphans.schema.json` |
| `prune-relations` | `prune-relations.schema.json` |
| `reclassify-relation` | `reclassify-relation.schema.json` |
| `split-body` (v1.1.03, GAP-V8) | `split-body.schema.json` |
| `entity_connect_seen` (v1.1.04, GAP-002) | implícito via migração V016 — grava `(source_id, target_id, namespace, verdict, relation, evaluated_at)` |
| `normalize-entities` | `normalize-entities.schema.json` |
| `enrich` (evento de fase) | `enrich-phase.schema.json` |
| `enrich` (evento por item) | `enrich-item-event.schema.json` |
| `enrich` (sumário, atualizado v1.0.84, ADR-0042) | `enrich-summary.schema.json` |
| `enrich --status` (v1.0.96, GAP-ENRICH-BACKLOG-CONVERGE) | `enrich-status.schema.json` |
| `config list` / `config list --effective` | `config-list.schema.json` |
| `ingest` (evento por arquivo) | `ingest-file-event.schema.json` |
| `ingest` (sumário, atualizado v1.0.84, ADR-0042) | `ingest-summary.schema.json` |
| (modo aposentado, evento de fase — arquivo preservado) | `ingest-claude-phase.schema.json` |
| (modo aposentado, evento por arquivo — alias DESCONTINUADO) | `ingest-claude-file-event.schema.json` |
| (modo aposentado, sumário — alias DESCONTINUADO) | `ingest-claude-summary.schema.json` |
| `debug-schema` | `debug-schema.schema.json` |
| `fts rebuild` | `fts-rebuild.schema.json` |
| `fts check` | `fts-check.schema.json` |
| `fts stats` | `fts-stats.schema.json` |
| `backup` | `backup.schema.json` |
| `delete-entity` | `delete-entity.schema.json` |
| `reclassify` | `reclassify.schema.json` |
| `merge-entities` | `merge-entities.schema.json` |
| `rename-entity` | `rename-entity.schema.json` |
| `memory-entities` (forward: `--name`) | `memory-entities.schema.json` |
| `memory-entities` (reverso: `--entity`) | `memory-entities-reverse.schema.json` |
| `prune-ner` | `prune-ner.schema.json` |
| `remember-batch` (evento por item) | `remember-batch.schema.json` |
| `remember-batch` (sumário) | `remember-batch-summary.schema.json` |
| `export` (linha por memória) | `export-memory-line.schema.json` |
| `export` (sumário) | `export-summary.schema.json` |
| `vec orphan-list` (v1.0.69) | `vec-orphan-list.schema.json` |
| `vec purge-orphan` (v1.0.69) | `vec-purge-orphan.schema.json` |
| `vec stats` (v1.0.69) | `vec-stats.schema.json` |
| `slots status` (v1.0.82, GAP-004) | `slots-status.schema.json` |
| `embedding status` (v1.0.82, GAP-005, atualizado v1.0.84, ADR-0042) | `embedding-status.schema.json` |
| `embedding list` (v1.0.82, GAP-005) | `embedding-list.schema.json` |
| envelope de shutdown (v1.0.82, GAP-002) | `shutdown-envelope.schema.json` |
| envelope de erro (todos os comandos) | `error-envelope.schema.json` |
### Mudanças de Schema na v1.1.8 (qualidade/latência/contrato do enrich)
- **Sem migração main-DB obrigatória.** `CURRENT_SCHEMA_VERSION` permanece em **16**. O sidecar do enrich pode ganhar coluna opcional `priority` via ALTER idempotente.
- `remember.schema.json` — campos opcionais aditivos `entities_created` (string[]) e `enrich_recommended` (string[]) para orquestração de hot-set (GAP-CLI-PRIO-01). Par com a flag `remember --enqueue-enrich`.
- `memory-entities.schema.json` — itens forward exigem `description` (string; vazia se ausente) para paridade com o lookup reverso (GAP-CLI-ME-01).
- `enrich-status.schema.json` — campos de qualidade/status: `scan_backlog_empty`, `scan_backlog_low_quality`, `force_redescribe`, `quality_pct`, `quality_sample_n`, `scan_backlog_low_grounding_est`; `state` inclui `blocked_dead` (QISO).
- `enrich-summary.schema.json` — opcionais `budget_exhausted`, `pairs_remaining_estimate`, `yields`, `preempted_for_gate`.
- Flag curta `-o` de `deep-research` é alias CLI de `--output`; schema de ack inalterado.
- Gate offline: `scripts/e2e_offline_v120.sh` (**20/20**). Help não deve anunciar product env `SQLITE_GRAPHRAG_*` como config.
### Notas de Schema na v1.2.2 (subcomando `schema` — sem mudança de campos)
- **Sem migração main-DB obrigatória.** `CURRENT_SCHEMA_VERSION` permanece em **16**. Crate **1.2.2**.
- **Novo subcomando `schema`** — o catálogo dos **75** contratos deixa de exigir que o agente liste `docs/schemas/` no disco:
- `sqlite-graphrag schema` emite **NDJSON**, uma linha por contrato, no formato `{"id","invoke"}`; `invoke` já traz o comando pronto para copiar
- `sqlite-graphrag schema --name <ID>` emite o documento JSON Schema daquele contrato
- `<ID>` desconhecido sai com **exit 4** (not found), nunca com um catálogo vazio
- `--json` não muda a saída da listagem: ela já é NDJSON por definição
- **Documentos `$schema` são isentos da superfície agent-native.** `--filter`, `--select` e os demais knobs da v1.2.2 nunca remodelam um documento de contrato; ele é reconhecido pelo membro `$schema` e passa intacto. Um agente pode encadear `schema --name <ID>` com qualquer flag global sem corromper o contrato.
- **Contrato NDJSON do `--mode claude-code` unificado (GAP-SG-148 item 5).** O modo deixou de reportar por um tipo paralelo: eventos por arquivo e sumário usam os **mesmos `IngestFileEvent` / `IngestSummary`** do pipeline padrão.
- `status` por arquivo é **`indexed`** quando a memória foi escrita — **não `done`**. Enum completa: `indexed`, `failed`, `skipped`, `preview`
- O sumário reporta **`files_total`, `files_succeeded`, `files_failed`, `files_skipped`** — **não `completed`**
- `entities`, `rels` e `cost_usd` são membros opcionais do tipo compartilhado: carregam valor nos modos LLM e são omitidos no wire pelo pipeline padrão, então uma linha de `--mode none` continua idêntica byte a byte ao que era antes da unificação
### Notas de Schema na v1.2.1 (CAPA enrich — sem mudança de campos de schema)
- **Sem migração main-DB obrigatória.** `CURRENT_SCHEMA_VERSION` permanece em **16**. Crate **1.2.2** (nota da v1.2.1 mantida abaixo; a superfície de saída agent-native não acrescenta campo de schema).
- **Somente comportamento do sidecar** — lista CAPA completa (nenhum campo novo de stdout):
1. `dequeue_next_pending` — claim por `operation` **e** `namespace`
2. `count_eligible_pending` para `--until-empty` — conta **só op+ns**
3. `reopen_force_redescribe_candidates` — reabre `skipped`/`done` uma vez por processo; **nunca** `dead`
4. `reconcile_satisfied_reembed_pending` — marca ReEmbed pending como `done` quando o BLOB vivo casa (`LENGTH(embedding) = dim*4`); limpa zumbis sem chamadas de API
5. Elegibilidade de re-embed por **LENGTH** do BLOB, não só a coluna `dim` (linhas CORRUPT re-embedam)
6. Strip do prefixo `entity:` no lookup de enqueue (chave da fila permanece `entity:…`)
7. Enqueue de chunk valida namespace (memória não-deletada no ns alvo)
8. CAPA-D — apenas marcadores compostos de "configuration file"
- **`enrich-status.schema.json` / `enrich-summary.schema.json` inalterados** — nenhuma mudança de campo de schema esperada para o selo CAPA; agentes continuam Must-Ignore em chaves desconhecidas.
- Gate offline permanece `scripts/e2e_offline_v120.sh` (**20/20** PASS).
- Regressões: `enqueue_candidate_accepts_entity_prefixed_reembed_key`, `dequeue_next_pending_isolates_by_namespace`; suite da fila **38** OK.
### Notas de Schema na v1.2.0 (selo de produto — sem novos arquivos de schema)
- **Sem migração main-DB obrigatória.** `CURRENT_SCHEMA_VERSION` permanece em **16**. Crate **1.2.0**.
- **`DEFAULT_EMBEDDING_DIM=1024`** — `init` grava `schema_meta.dim` a partir do default (ou override `--embedding-dim` / XDG). Bancos existentes mantêm o dim carimbado até re-embed. Mudança de constante de runtime/init, **não** um novo arquivo `*.schema.json`.
- **`enrich --list-skipped` / `enrich --requeue-skipped`** — sink recuperável de `skipped`/preservation (espelha `--list-dead` / `--requeue-dead`). **Sem novo schema**: list/requeue reutilizam o envelope do inspetor dead (`DeadItem` + `DeadSummary` com `action: "list-skipped"` / `"requeue-skipped"`). Se o payload parecer enrich-status ou trouxer campos observacionais extras, agentes **DEVEM** tratar chaves desconhecidas como Must-Ignore (não falhar de forma rígida).
- **GAP-SG-139 é apenas contrato de entrada CLI** (sem mudança de schema): folhas host/XDG (`config`, `slots`, `cache`, `completions`) aceitam `--db` como **no-op** documentado para que agentes que anexam `--db` em toda invocação não recebam clap exit 2. Subcomandos de grafo continuam abrindo o DB.
- O índice já cobre `config-list.schema.json` para `config list` / `config list --effective`. **Não** existe `cache.schema.json` (veja Comandos Sem JSON Schema).
- Gate offline permanece `scripts/e2e_offline_v120.sh` (**20/20** PASS).
### Comandos Sem JSON Schema (PT)
- `completions` emite scripts de completion de shell (Bash, Zsh, Fish, PowerShell, Elvish) como texto puro — nenhum schema JSON se aplica
- `help` / `--help` é meta da CLI (texto puro) — nenhum schema JSON se aplica
- `cache` (`list` / `stats` / `clear-models`) **não** tem `cache.schema.json` dedicado; a saída JSON é informal/operacional (lista + tamanhos). Agentes devem tratar campos inesperados como Must-Ignore. Cobertura do comportamento de cache está nos monógrafos (`HOW_TO_USE`, `COOKBOOK`, `AGENTS`), não neste índice de schemas
- `daemon` foi removido na v1.0.76 (código restante deletado na v1.0.79) — nenhum schema JSON se aplica (histórico)
### Mudanças de Schema na v1.1.05 (ADR-0065)
- **Sem migração de banco obrigatória.** `CURRENT_SCHEMA_VERSION` permanece em **16**. Operadores **não** precisam de `migrate` nesta release.
- `deep-research` — `sub_queries[].source` também emite `aspect` (fan-out de facetas em token único) e `manual` (`--sub-query-strategy manual --sub-queries-file PATH`). O enum em `deep-research.schema.json` na v1.1.05 é `original | decomposed | aspect | manual`. Nenhum campo *obrigatório* novo no envelope completo.
- `deep-research --output PATH` — quando definido, o stdout é um **ack** curto após atomwrite (tempfile no mesmo diretório → fsync → rename); o envelope completo fica em disco. Schema dedicado: `deep-research-output-ack.schema.json` (Bug 2 / ADR-0065). Campos obrigatórios: `written` (caminho string), `bytes` (tamanho u64 do arquivo), `blake3` (digest hex dos bytes gravados), `sub_queries_total` (usize), `unique_memories_found` (usize), `elapsed_ms` (u64). `additionalProperties: false`. Suite de regressão: `tests/v1105_incident_bugs_regression.rs`.
- `link --from-id` / `--to-id` — **apenas flags de entrada CLI**. O envelope de **saída** de `link.schema.json` permanece inalterado (`from`/`to` continuam sendo **nomes** de entidade após resolução). Strings só de dígitos são rejeitadas como nomes (`validate_entity_name`); isso é comportamento de validação, não uma nova propriedade JSON. A descrição do schema menciona as flags por ID.
- `graph traverse --fuzzy` — UX de resolução: com `--fuzzy`, o campo `from` em `graph-traverse.schema.json` é o **nome canônico resolvido** (pode diferir do argumento CLI `--from`). Sugestões de nome em NotFound permanecem apenas UX de erro.
- Global `--quiet` / `-q` — afeta apenas o volume de tracing em stderr; sem impacto no schema de stdout.