Repository navigation
Home
Welcome to the Wiki_textgraph wiki!
Turn a pile of case documents into a queryable, byte-cited knowledge graph — deterministic & local-first by default. Explore it in an interactive graph studio, derive new relations with link prediction & Datalog rules, and layer opt-in LLM extraction, grounded answer synthesis, and semantic search on top (always
GENERATED-quarantined, never masquerading as ground truth).
-
PyPI:
pip install textgraph-kg(import package + CLI:textgraph) - Live demo: https://krishddd.github.io/Wiki_textgraph/
- License: MIT
TextGraph helps investigators make sense of financial-crime and technical-crime evidence: filings, contracts, wire-transfer logs, SARs, memos, chat/email exports, reports. It ingests that corpus and emits a structured, versioned graph that shows who is connected to whom, through what, and — crucially — why — with every edge carrying the exact source span that supports it, so a finding can be re-verified and stands up to audit.
It is the natural-language successor to llm-wiki: where llm-wiki gave an agent cited, streaming answers, TextGraph generalizes that to any textual corpus and produces a graph an agent can traverse.
Most GraphRAG tools build the graph with an LLM: extraction is non-deterministic, edges arrive without verifiable sources, and you can't reproduce or audit the result. TextGraph inverts that — the edge is trust, not just recall:
-
🔁 Deterministic by construction — the same corpus always produces a byte-identical
graph.json, gated in CI. Diff two runs, reproduce any finding. -
🔍 Byte-level provenance on every edge — each non-generated claim carries the exact
[doc:start-end]span and re-hashes against source bytes; 100% re-verification is gated. -
🚫 Zero LLM calls by default — ingest → IE → resolution → claims → analytics → retrieval runs locally, CPU-only, no API key. LLMs are opt-in, quarantined, and
GENERATED-tagged. -
🕓 Bi-temporal versioning — claims carry
[t_valid, t_invalid)windows; a later fact invalidates an earlier one (citedSUPERSEDES) rather than overwriting it. - 📏 Honest about quality — publishes the hallucinated-edge rate, a number most systems don't report.
pip install textgraph-kg → textgraph build ./docs already does the investigator happy path — no flags, no API key, no server:
- 📄 PDFs ingest by default (
pypdfis a core dep);.docx/.html/.epub/logs/chat too. - 🔗 Entity resolution on by default —
Acme Corporation/Acme Corp/ACMEcollapse to one canonical identity via citedSAME_AS. - 🔎 Hybrid retrieval by default — BM25 + Personalized PageRank + RRF, every hit cited.
- 🧠 LLM & embeddings opt-in —
--llm-extract,--narrate,--embed, alwaysGENERATED-quarantined.
Each layer is a pure function of the layer below it plus a pinned config hash — the property that makes determinism (G1) and incrementality (G5) achievable.
flowchart TD
IN["📄 Case corpus<br/>PDF · DOCX · ODT · RTF · HTML · EPUB · JSON/YAML · logs · chat"]
subgraph SPINE["🟢 Structural spine (zero LLM, deterministic)"]
L0["L0 · Ingest & Normalize<br/>CanonicalDoc = UTF-8 + offset map + block tree + chunks"]
L1["L1 · Deterministic Structure<br/>sections, links, definitions, citations, Rationale & Requirement"]
L0 --> L1
end
subgraph SEM["⚪ Extraction (deterministic core + opt-in enrichers)"]
L2["L2 · coref · temporal · negation"]
L3["L3 · Encoder IE · entities + typed relations (EXTRACTED)"]
XLLM["🧠 --llm-extract · chunk → LLM → triples (GENERATED)"]
XCO["🔗 --co-occurrence · co-mentioned entities (STRUCTURAL)"]
L2 --> L3 --> XLLM
L3 --> XCO
end
subgraph GRAPH["⚪ Resolution & graph model (deterministic)"]
L5["L5 · Entity resolution · SAME_AS lattice, non-destructive"]
L6["L6 · Claim reification · reified Claims + t_valid + invalidation"]
end
subgraph RETR["🟢 Analytics & retrieval (zero LLM, deterministic)"]
L7["L7 · PageRank · communities · layout · bridges · contradictions"]
L8["L8 · Retrieval · dual-node graph · BM25 + PPR + RRF"]
L7 --> L8
end
L4["🧠 L4 · --llm synthesis (opt-in) · GENERATED summaries"]
L9["📦 L9 · Artifacts + MCP · graph.json · graph.html · GRAPH_REPORT.md"]
IN --> L0
L1 --> L2
L3 --> L5
XLLM -.-> L5
XCO -.-> L5
L5 --> L6 --> L7
L7 -.-> L4 -.-> L9
L8 --> L9
The deterministic core — L0 → L1 → L2/L3 → L5 → L6 → L7 → L8 — never calls a model. The LLM appears at exactly two opt-in, GENERATED-quarantined touchpoints: relation extraction (input enricher, runs before resolution/analytics) and synthesis/narration (output pass). Turn both off and the build is byte-identical.
Every edge is tagged STRUCTURAL, EXTRACTED, INFERRED, or GENERATED. Merging node identity never launders an edge's tag — a model-authored relation between two EXTRACTED entities stays GENERATED and filterable (one-click in the console, tag: "GENERATED" in graph.json).
pip install textgraph-kg
# Deterministic, offline build:
textgraph build ./case-files -o textgraph-out
# → graph.json, GRAPH_REPORT.md, graph.html, schema.yaml, manifest.json
# Query the graph directly — bounded, byte-cited answers, no LLM:
textgraph query ./case-files "who transferred funds to whom"
textgraph path ./case-files "Acme Corp" "Gamma Holdings"
textgraph explain ./case-files "Acme Corp"
textgraph timeline ./case-files "Acme Corp"
textgraph contradictions ./case-files
# Interactive graph console (canvas viewer + all eight tools):
textgraph console ./case-files # → http://127.0.0.1:8765
# Standard GQL (ISO/IEC 39075 / Cypher subset):
textgraph gql ./case-files "MATCH (a:Organization)-[:CONTROLS*1..3]->(b) RETURN a.name, b.name"Python API — build once, then call the eight typed, cited tools:
from textgraph.pipeline import build
from textgraph.l8_retrieval import QueryEngine
result = build("./case-files") # deterministic; byte-identical graph.json
engine = QueryEngine(result.nodes, result.edges)
hits = engine.search("who transferred funds to whom", k=5)
engine.path("Acme Corp", "Gamma Holdings") # max-likelihood cited path
engine.why("Acme Corp") # cited claims + validity windows
engine.conflicts() # single-truth conflicts, surfaced not mergedG1 determinism · G2 local-first · G3 provenance (no assertion without a re-verifiable byte-range citation) · G4 confidence stratification · G5 incrementality · G6 agent-legible output (bounded, ranked, cited context — never raw Cypher) · G7 bounded, auditable cost.
The full L0–L9 stack is shipped (deterministic ingest → IE → resolution → bi-temporal claims → analytics → hybrid retrieval → optional LLM) with CLI, MCP, and a dependency-free local web console. Recent releases add openCypher export → Neo4j, forward-chaining Datalog rules, structural link prediction, GQL, vision-native retrieval, fine-grained access control (ReBAC + ABAC), and Graph-of-Thoughts reasoning. See CHANGELOG.md and PLAN.md.
-
ARCHITECTURE.md,docs/how-it-works.md,docs/retrieval-routing.md -
BENCHMARKS.md— recall@k / MRR with tokens-per-query and latency ("no number without its cost") -
docs/COMPARISON_SEMANTICA.md— honest comparison with the closest peer -
docs/RUNNING.md— step-by-step getting-started guide