sqlite-graphrag 1.2.8

Persistent GraphRAG memory for Claude Code, Codex, Cursor, and 27 AI agents — one self-contained ~19 MiB Rust binary, zero daemon. Never re-explain your codebase again. Hybrid retrieval (FTS5 BM25 + cosine similarity + multi-hop graph traversal) surfaces the right memory in milliseconds. Embedding and entity enrichment run as parallel REST calls against your cloud LLM — no fragile headless subprocesses, no ONNX runtime, no model downloads. Soft-delete with full version history, transactional atomic writes, BLAKE3-tracked mutations. OAuth-only: raw API keys ABORT the spawn.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
# 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.