sqlite_graphrag/commands/ingest/mod.rs
1//! Handler for the `ingest` CLI subcommand.
2//!
3//! Bulk-ingests every file under a directory that matches a glob pattern.
4//! Each matched file is persisted as a separate memory using the same
5//! validation, chunking, embedding and persistence pipeline as `remember`,
6//! but executed in-process so the ONNX model is loaded only once per
7//! invocation. This is the v1.0.32 Onda 4B (finding A2) refactor that
8//! replaced a fork-spawn-per-file pipeline (every file paid the ~17s ONNX
9//! cold-start cost) with an in-process loop reusing the warm embedder
10//! (daemon when available, in-process `Embedder::new` otherwise).
11//!
12//! Memory names are derived from file basenames (kebab-case, lowercase,
13//! ASCII alphanumerics + hyphens). Output is line-delimited JSON: one
14//! object per processed file (success or error), followed by a final
15//! summary object. Designed for streaming consumption by agents.
16//!
17//! ## Incremental pipeline (v1.0.43)
18//!
19//! Phase A runs on a rayon thread pool (size = `--ingest-parallelism`):
20//! read + chunk + embed + NER per file. Results are sent immediately via a
21//! bounded `mpsc::sync_channel` to Phase B so persistence starts as soon
22//! as the first file completes — no waiting for all files to finish Phase A.
23//!
24//! Phase B runs on the main thread: receives staged files from the channel,
25//! writes to SQLite per-file (WAL absorbs individual commits), and emits
26//! NDJSON progress events to stderr as each file is persisted. `Connection`
27//! is not `Sync` so it never crosses thread boundaries.
28//!
29//! This fixes B1: with the old 2-phase design, a 50-file corpus with 27s/file
30//! NER would spend ~22min in Phase A alone, exceeding the user's 900s timeout
31//! before Phase B (and any DB writes) could begin. With this pipeline, the
32//! first file is committed within seconds of starting.
33
34// Submodules (R-SRP-01), split by responsibility rather than by size.
35// Pipeline stages, in execution order: validate (flag checks) -> scan_fs
36// (walk) -> plan (name resolution) -> dry_run (preview) -> stage_producer
37// (Phase A) -> stage (per-file work) -> persist_loop (Phase B) -> persist
38// (per-file write) -> enrich_after (optional binding pass). `run` orchestrates
39// them; `args` and `report` carry the CLI surface and the NDJSON types.
40mod args;
41mod dry_run;
42mod enrich_after;
43mod persist;
44mod persist_loop;
45mod plan;
46mod report;
47mod run;
48mod scan_fs;
49mod stage;
50mod stage_producer;
51mod validate;
52
53pub use args::{IngestArgs, IngestMode};
54pub use run::run;
55
56#[cfg(test)]
57#[path = "../ingest_tests.rs"]
58mod tests;