D-Knowledge Graph
Provides a GitHub Action for consuming the knowledge graph and running automated tests or benchmarks in a GitHub Actions workflow.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@D-Knowledge GraphWhat is the provenance of the claim that sales increased in Q3?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Everything runs on your own computer. There is no cloud call, no telemetry, and nothing required beyond Python itself. Where this document gives an accuracy figure, that figure comes from a measurement you can run again yourself.
Start here
Three commands take you from a clone to a graph you can question. None of them touches the network.
pip install -e . # no runtime dependencies
dkg init # create a project-local .dkg home
dkg ingest ./my-notes -r # then: dkg search "a phrase you expect to find"Analysing a repository instead? Run pip install -e ".[code]", then dkg code-ingest ./my-repo and dkg code-hubs.
One measured result, stated the way it was measured. Turning on type-aware resolution takes the precision of a change-impact query from 0.1081 to 1.0, with recall held at 1.0, on a sample of 42 evaluation nodes and 24 true edges per language, for Python and JavaScript. The default was never missing real impact; it was reporting far too much of it. That is one measurement on one sample, regenerated by python scripts/benchmark.py, and it is not a prediction about your repository.
Related MCP server: ragi
Overview
D-Knowledge Graph is one shared knowledge-graph core with two analysis planes on top of it.
The core is a SQLite store with full-text search, stable content-derived identifiers, a tamper-evident audit log, a record of where every fact came from, and a read-only connection for AI assistants. The two planes share that foundation and one standard of evidence:
A document and media plane that reads text, structured data, web content, images, video, and audio, then extracts entities and claims and grades each one with a confidence you can inspect.
A source-code plane that parses 42 languages and containers into a code graph and answers structural questions: what a change touches, how execution flows, where the architectural chokepoints are, which connections are surprising, and what is untested.
Search runs keyword matching, full-text search, and a hybrid path that fuses the two, with an optional local embedding model and an optional reranker that load from files already on disk. Graph structure is summarized by two detectors this project wrote itself, Mnemosyne and Ariadne. Around all of it sits a delivery layer: a repository watcher, an offline graph viewer, exports to other tools, and a ready-made GitHub Action.
The problem it solves
Problem | How D-Knowledge Graph answers it |
Knowledge tools send your data to a service you cannot inspect. | Everything runs locally against a SQLite file. Outbound network is off, and every path that could reach out needs an explicit flag. |
An answer cannot be traced back to its source. | Every record carries where it came from, every claim carries its evidence and a confidence you can read, and one command verifies the audit log has not been altered. |
Quality claims are marketing rather than measurement. | Search, grouping, code resolution, execution flow, and media accuracy are measured on documented samples with a fixed seed, and published in |
Reviewing the impact of a code change needs a hosted service. | The code plane parses in your own process with permissive grammars and computes impact over the local graph, with no account and no network. |
An assistant reaching your data can be instructed by that data. | The assistant connection is read-only, fetched web content is labelled as evidence and never as instructions, and security decisions run outside the model. |
How it works
One shared core, two planes. The core owns storage, search, evidence, and the assistant connection. Each plane brings its own readers and writes into the same graph, so a question can cross from a document to the code it describes.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#e4e4e4","primaryTextColor":"#404040","primaryBorderColor":"#a5a5a5","lineColor":"#757575","secondaryColor":"#d4d4d4","tertiaryColor":"#f4f4f4","clusterBkg":"#f4f4f4","clusterBorder":"#a5a5a5","edgeLabelBackground":"#f4f4f4","textColor":"#404040"}}}%%
flowchart TB
subgraph inputs["Your data, never leaves the machine"]
docs["Documents<br/>text, markdown, json, csv, docx, pdf"]
media["Media<br/>images, video, audio"]
code["Source code<br/>42 languages and containers"]
end
subgraph planes["Analysis planes"]
dmp["Document and media plane<br/>readers, OCR, ASR, keyframes, detection<br/>entity and claim extraction"]
scp["Source-code plane<br/>Tree-sitter parsers, code graph<br/>impact, flow, centrality, coupling"]
end
subgraph core["Shared knowledge-graph core"]
store["SQLite store<br/>entities, relationships, chunks"]
search["Search<br/>keyword, FTS5, hybrid, rerank"]
evid["Evidence ledger<br/>provenance, confidence, audit chain"]
end
surfaces["Surfaces<br/>CLI, read-only MCP, exports, offline viewer"]
docs --> dmp
media --> dmp
code --> scp
dmp --> store
scp --> store
store <--> search
store <--> evid
search --> surfaces
evid --> surfaces
classDef outer fill:#f4f4f4,stroke:#a5a5a5,color:#404040
classDef inner fill:#e4e4e4,stroke:#a5a5a5,color:#404040
classDef strong fill:#d4d4d4,stroke:#757575,color:#282828
class docs,media,code outer
class dmp,scp,store,search,evid inner
class surfaces strongThe two planes stay separate on purpose. They share the foundation and one standard of evidence, but never each other's readers.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#e4e4e4","primaryTextColor":"#404040","primaryBorderColor":"#a5a5a5","lineColor":"#757575","secondaryColor":"#d4d4d4","tertiaryColor":"#f4f4f4","clusterBkg":"#f4f4f4","clusterBorder":"#a5a5a5","edgeLabelBackground":"#f4f4f4","textColor":"#404040"}}}%%
flowchart LR
subgraph dm["Document and media plane"]
direction TB
r1["Readers<br/>stdlib formats, html, pdf, rss"]
r2["Media<br/>EXIF, OCR, ffprobe, keyframes, ASR"]
r3["Extraction<br/>entities, claims, relations, dedupe"]
r1 --> r3
r2 --> r3
end
subgraph sc["Source-code plane"]
direction TB
c1["Tree-sitter parse<br/>symbols and references"]
c2["Edge resolution<br/>name-based, optional type-aware"]
c3["Analysis<br/>blast-radius, flow, hubs, coupling, gaps"]
c1 --> c2 --> c3
end
shared[("Shared core<br/>entities, relationships, chunks,<br/>provenance, evidence, audit")]
r3 --> shared
c3 --> shared
classDef inner fill:#e4e4e4,stroke:#a5a5a5,color:#404040
classDef strong fill:#d4d4d4,stroke:#757575,color:#282828
class r1,r2,r3,c1,c2,c3 inner
class shared strongA query never guesses. It fans out across the search paths, fuses the results, and returns the evidence with every hit.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#e4e4e4","primaryTextColor":"#404040","primaryBorderColor":"#a5a5a5","lineColor":"#757575","secondaryColor":"#d4d4d4","tertiaryColor":"#f4f4f4","clusterBkg":"#f4f4f4","clusterBorder":"#a5a5a5","edgeLabelBackground":"#f4f4f4","textColor":"#404040"}}}%%
flowchart LR
q["Question<br/>CLI or MCP tool"] --> plan{"Which surface?"}
plan -->|search| kw["Keyword"]
plan -->|search| fts["FTS5"]
plan -->|search| vec["Vector similarity<br/>optional embeddings"]
kw --> fuse["Rank fusion"]
fts --> fuse
vec --> fuse
fuse --> rr["Cross-encoder rerank<br/>optional, degrades cleanly"]
rr --> ev["Attach evidence<br/>provenance, confidence, source"]
plan -->|graph| trav["Bounded traversal<br/>neighbourhood, impact, flow"]
trav --> ev
ev --> ans["Answer with citations<br/>every hit traceable to a document"]
classDef inner fill:#e4e4e4,stroke:#a5a5a5,color:#404040
classDef strong fill:#d4d4d4,stroke:#757575,color:#282828
classDef outer fill:#f4f4f4,stroke:#a5a5a5,color:#404040
class q,plan outer
class kw,fts,vec,fuse,rr,trav inner
class ev,ans strongSearch quality is measured on 30 documents and 40 queries. Keyword matching alone scores MRR 0.9375 and nDCG@10 0.9473. Adding the optional embedding model and reranker takes both to 1.0, at an added 205.84 ms per query.
One measured before and after
Type-aware resolution is the clearest measured improvement in the project, and it is also the clearest illustration of why the default result is advisory. Matching by name alone resolves a call to every function that shares the name, so a change-impact query flags far too much. With a language server installed, the same query resolves to one target.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#e4e4e4","primaryTextColor":"#404040","primaryBorderColor":"#a5a5a5","lineColor":"#757575","secondaryColor":"#d4d4d4","tertiaryColor":"#f4f4f4","clusterBkg":"#f4f4f4","clusterBorder":"#a5a5a5","edgeLabelBackground":"#f4f4f4","textColor":"#404040"}}}%%
flowchart LR
subgraph before["Before: structural name matching (default)"]
b1["Blast-radius precision<br/><b>0.1081</b>"]
b2["Recall<br/>1.0"]
b3["Every same-named<br/>candidate flagged"]
end
subgraph after["After: type-aware resolution (--resolve)"]
a1["Blast-radius precision<br/><b>1.0</b>"]
a2["Recall<br/>1.0"]
a3["One resolved target<br/>per call site"]
end
before --> after
classDef inner fill:#e4e4e4,stroke:#a5a5a5,color:#404040
classDef strong fill:#d4d4d4,stroke:#757575,color:#282828
class b1,b2,b3 inner
class a1,a2,a3 strongMeasured on 42 evaluation nodes and 24 true edges per language, for Python and JavaScript. Go stays structural because no language server is installed for it here. Recall is 1.0 in both settings, so the whole gain is in precision.
What a change-impact query actually computes
It walks the code graph backwards: start at the changed symbol, follow inbound connections, stop at the depth limit. It deliberately over-reports, which is why the result is advisory and why the comparison above matters.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#e4e4e4","primaryTextColor":"#404040","primaryBorderColor":"#a5a5a5","lineColor":"#757575","secondaryColor":"#d4d4d4","tertiaryColor":"#f4f4f4","clusterBkg":"#f4f4f4","clusterBorder":"#a5a5a5","edgeLabelBackground":"#f4f4f4","textColor":"#404040"}}}%%
flowchart RL
changed["Changed symbol<br/>parse_config()"]
d1a["loader.load()"]
d1b["cli.main()"]
d2a["service.boot()"]
d2b["tests/test_loader.py"]
d3["api.handler()"]
d1a -- calls --> changed
d1b -- calls --> changed
d2a -- calls --> d1a
d2b -- covers --> d1a
d3 -- calls --> d2a
subgraph depths[" "]
direction RL
note["Depth 1: 2 symbols<br/>Depth 2: 4 symbols<br/>Depth 3: 5 symbols<br/>bounded, then it stops"]
end
classDef inner fill:#e4e4e4,stroke:#a5a5a5,color:#404040
classDef strong fill:#d4d4d4,stroke:#757575,color:#282828
classDef outer fill:#f4f4f4,stroke:#a5a5a5,color:#404040
class changed strong
class d1a,d1b inner
class d2a,d2b,d3 outer
class note outerThe symbol names above illustrate the shape rather than report a measurement.
Re-reading only what changed
A second run does not re-parse the repository. The incremental path asks version control which files moved, re-parses those, and replaces only their symbols and connections.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#e4e4e4","primaryTextColor":"#404040","primaryBorderColor":"#a5a5a5","lineColor":"#757575","secondaryColor":"#d4d4d4","tertiaryColor":"#f4f4f4","clusterBkg":"#f4f4f4","clusterBorder":"#a5a5a5","edgeLabelBackground":"#f4f4f4","textColor":"#404040"}}}%%
flowchart LR
trigger["dkg code-ingest --since REF<br/>or the watch daemon"] --> ask{"Changed<br/>since last run?"}
ask -- "no" --> skip["Nothing re-parsed"]
ask -- "yes, N files" --> parse["Re-parse those N files"]
parse --> replace["Replace their symbols<br/>and edges only"]
replace --> reuse["Everything else<br/>stays as it was"]
reuse --> updatedGraph[("Updated code graph")]
skip --> updatedGraph
classDef inner fill:#e4e4e4,stroke:#a5a5a5,color:#404040
classDef strong fill:#d4d4d4,stroke:#757575,color:#282828
classDef outer fill:#f4f4f4,stroke:#a5a5a5,color:#404040
class trigger,ask outer
class parse,replace,reuse,skip inner
class updatedGraph strongThis path is covered by tests, for both git and Subversion. Its speed has never been timed, so this project publishes no timing claim for it.
Asking about everything, or just the part that answers your question
The graph route answers a structural question with the nodes that answer it, plus the files those nodes name. On a sample of 38 Python files holding 12,620 estimated tokens, 289 symbols, and 745 connections, the two routes cost this:
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#e4e4e4","primaryTextColor":"#404040","primaryBorderColor":"#a5a5a5","lineColor":"#757575","secondaryColor":"#d4d4d4","tertiaryColor":"#f4f4f4","clusterBkg":"#f4f4f4","clusterBorder":"#a5a5a5","edgeLabelBackground":"#f4f4f4","textColor":"#404040"}}}%%
flowchart TB
ask["Question: where are the chokepoints?"]
subgraph whole["Hand over every file"]
w1["38 files"]
w2["<b>12,620 tokens</b>"]
end
subgraph targeted["Ask the graph"]
t1["Answer plus the 10 files it names"]
t2["<b>7,118 tokens</b>"]
end
ask --> whole
ask --> targeted
targeted --> verdict["Ratio <b>1.773</b> on this question"]
whole --> verdict
classDef inner fill:#e4e4e4,stroke:#a5a5a5,color:#404040
classDef strong fill:#d4d4d4,stroke:#757575,color:#282828
classDef outer fill:#f4f4f4,stroke:#a5a5a5,color:#404040
class ask outer
class w1,w2 inner
class t1,t2 inner
class verdict strongAcross five questions on that sample the mean ratio is 1.4232, ranging from 0.6675 to 1.773. A ratio below 1.0 means the graph route cost more than simply handing over every file, which is what happens when a question's answer names the whole repository.
The size dependence is measured rather than assumed: at 13 files the mean ratio is 0.5838, at 23 files 0.9321, at 38 files 1.4232. A repository small enough to fit in a context window does not need a graph to save tokens.
Mnemosyne and Ariadne
A graph of any real size is too large to read. Two detectors, both written for this project, turn it into a handful of groups you can actually work with. Both run by default, and the platform returns whichever one scores higher on the measurement.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#e4e4e4","primaryTextColor":"#404040","primaryBorderColor":"#a5a5a5","lineColor":"#757575","secondaryColor":"#d4d4d4","tertiaryColor":"#f4f4f4","clusterBkg":"#f4f4f4","clusterBorder":"#a5a5a5","edgeLabelBackground":"#f4f4f4","textColor":"#404040"}}}%%
flowchart LR
rel[("Your graph<br/>entities and their connections")]
base["Mnemosyne<br/>base pass, no dependency"]
refine["Ariadne<br/>refinement pass, optional meaning"]
pick{"Which scores<br/>higher?"}
out["The returned grouping,<br/>with both passes reported"]
rel --> base --> pick
rel --> refine --> pick
pick --> out
classDef inner fill:#e4e4e4,stroke:#a5a5a5,color:#404040
classDef strong fill:#d4d4d4,stroke:#757575,color:#282828
classDef outer fill:#f4f4f4,stroke:#a5a5a5,color:#404040
class rel outer
class base,refine,pick inner
class out strongBoth optimise modularity, the established published measure of how much better a grouping is than chance would produce. Modularity is not this project's invention and is not claimed as one. The two detectors are.
Mnemosyne, the base detector
What it does. Mnemosyne reads nothing but the connections and finds the groups hidden in them. It starts with every entity alone, moves each one into whichever neighbouring group improves the score most, then treats each group as a single entity and repeats on the smaller graph. Small clusters become topics, topics become areas.
Why it helps. It needs no model, no download, and no optional component. On a bare install it still turns a wall of connections into a readable map. It is also fully deterministic: the same graph always produces the same partition, byte for byte.
dkg community --detector mnemosyneMeasured. On a sample of 80 entities in 16 known groups it recovers the grouping exactly, agreement Rand 1.0, at modularity 0.846591 in 1.196 ms. On a sample of 40 entities in 5 topics whose connections are symmetric by design, it scores Rand 0.641, which is the expected result when the answer is not in the wiring.
Full explanation, mathematics, and results: docs/MNEMOSYNE.md.
Ariadne, the refinement detector
What it does. Ariadne takes the same graph and fixes three things the base pass cannot. It splits any group that turns out to be two disconnected halves, so every group it returns is one you could walk around. It can weight each connection by how similar the two ends are in meaning, when a local text model is installed. And it can choose its own granularity by trying a range of settings and keeping the best.
Why it helps. Two clusters can be wired identically and still be about completely different things. Structure alone cannot tell them apart, and Ariadne can.
dkg community --detector ariadneMeasured. On the structural sample the two detectors tie at Rand 1.0: the base pass was already exact and the refinement had nothing to fix. On the semantic sample Ariadne leads, Rand 0.7641 against 0.641, finding 8 groups against a true 5 where the base pass finds 4.
One detail worth knowing. Ariadne scores lower modularity on that semantic sample, 0.42 against 0.5, and since the default path returns the higher-scoring grouping, it returns the base pass there. Selection is by measurement and never by preference, so a tie or a lower score keeps the base result. When meaning matters more than wiring on your graph, ask for Ariadne directly with the command above.
Full explanation, mathematics, and results: docs/ARIADNE.md.
Capabilities
Everything below runs on the Python standard library alone unless the last column names an optional extra. Extras are opt-in and install with pip install -e ".[name]".
Capability | What it does | Needs |
Knowledge-graph store | SQLite with full-text search, stable identifiers, source tracking, and a tamper-evident audit log. | Built in |
Extraction | Entities, claims, and relationships, with no model required. | Built in |
Search | Keyword, full-text, and a hybrid path that reports which engines contributed. | Built in |
Local embeddings | Vector similarity from a local model, stored per model so two models never mix. |
|
Reranking | A local reranker over search results. Falls back cleanly when absent. |
|
Evidence and confidence | Per-claim evidence, a confidence you can read, and a contradiction scanner. | Built in |
Grouping | Mnemosyne and Ariadne, both running by default. | Built in |
Assistant connection | A read-only tool surface for AI assistants, plus a local-only HTTP option. | Built in |
Graph analysis | Hubs, bridges, chokepoints, surprising connections, gaps, review questions, and graph diffing. | Built in |
Editor setup | Write the assistant entry for an editor, with a dry run and a clean uninstall. | Built in |
Agent workflows | Deterministic research, validation, contradiction, and security-review agents. | Built in |
Source-code plane | 42 languages and containers, a code graph, change impact, execution flow, and optional type-aware resolution. |
|
Image detection | Local zero-shot image tagging. |
|
Media enrichment | Image decode and EXIF, OCR, video metadata, keyframes, and speech-to-text. |
|
Delivery | Repository watcher, offline graph viewer, exports, and a GitHub Action. | Built in; |
Benchmarks | One seeded command regenerates every measured number. | Built in |
A few of those rows deserve a sentence more.
The contradiction scanner groups claims about the same subject even when two documents phrase them differently, then tests them for conflicting numbers, negations, and opposites. It is a lexical scanner rather than a reasoning model, so its output is advisory: measured recall 0.6667 and precision 0.75.
The delivery layer is built in, including the repository watcher. The daemon runs out of the box on a polling backend from the standard library. Installing the optional watch extra swaps that for event-driven watching, which reacts faster and costs less while idle. Nothing else in the delivery layer needs an extra. Manage repositories with dkg registry add <name> <path> and run the watcher with dkg daemon.
Exports include an Obsidian vault. dkg export --format obsidian --out ./vault writes your graph as a folder of linked Markdown notes: one note per entity, with its connections as [[wikilinks]]. Opening that folder in the Obsidian note-taking app shows the graph in Obsidian's own graph view. Obsidian is a destination this platform writes to, not something it runs or requires. The other formats are json, markdown, csv, graphml, dot, cypher, svg, and a self-contained html viewer.
Supported inputs
These formats need nothing beyond the Python standard library:
Built-in input | Formats |
Text and Markdown |
|
Structured data |
|
Word documents |
|
RSS and Atom | feed parsing with the standard-library XML parser |
These are detected at run time. When the extra or the external tool is absent, the input steps aside with a clear reason rather than failing:
Optional input | Needs |
HTML |
|
| |
Web fetch |
|
Images, EXIF, OCR |
|
Video metadata, keyframes, scenes | external ffprobe and ffmpeg |
Speech-to-text | a local model referenced by |
Source code |
|
Language coverage
42 languages and containers, in four opt-in tiers plus one that needs no tier at all, so a minimal install stays minimal. Every grammar shipped is permissive, and none is copied into this repository.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#e4e4e4","primaryTextColor":"#404040","primaryBorderColor":"#a5a5a5","lineColor":"#757575","secondaryColor":"#d4d4d4","tertiaryColor":"#f4f4f4","clusterBkg":"#f4f4f4","clusterBorder":"#a5a5a5","edgeLabelBackground":"#f4f4f4","textColor":"#404040"}}}%%
flowchart TB
core["Core install<br/>zero runtime dependencies<br/>no language parsed"]
e1["<b>code</b><br/>5: Python, JavaScript, Go,<br/>Jupyter, Databricks"]
e2["<b>code-extended</b><br/>8: TypeScript, TSX, Java, Ruby,<br/>Rust, Vue, Svelte, Astro"]
e3["<b>code-full</b><br/>23: C, C++, C#, Swift, Kotlin, PHP,<br/>Scala, Dart, Elixir, Julia, Lua, Luau,<br/>Nix, Objective-C, PowerShell, Bash, Zsh,<br/>SQL, Solidity, Verilog, Zig, HCL, Ansible"]
e4["<b>code-bundle</b><br/>5: R, GDScript, ReScript,<br/>VB.NET, Perl"]
e5["<b>no extra</b><br/>1: Perl XS<br/>no grammar exists to install"]
total["<b>42</b> languages and containers"]
core --> e1 --> e2 --> e3 --> e4 --> e5 --> total
subgraph how["How each file is read"]
direction LR
g["<b>grammar</b>, 29<br/>a real Tree-sitter parse"]
c["<b>composite</b>, 7<br/>unwrapped first, then parsed<br/>by another language's grammar"]
f["<b>grammar or fallback</b>, 5<br/>grammar with code-bundle,<br/>pattern extractor without it"]
x["<b>fallback</b>, 1<br/>pattern extractor always,<br/>never called a parse"]
end
total --> how
classDef inner fill:#e4e4e4,stroke:#a5a5a5,color:#404040
classDef strong fill:#d4d4d4,stroke:#757575,color:#282828
classDef outer fill:#f4f4f4,stroke:#a5a5a5,color:#404040
class core outer
class e1,e2,e3,e4,e5 inner
class total strong
class g,c,f,x innerRun dkg code-languages for the live set on your machine. The full inventory, with extensions and licences, is in docs/LANGUAGES.md.
Extra | Languages and containers |
| Python, JavaScript, Go, Jupyter notebooks, Databricks notebooks |
| TypeScript, TSX, Java, Ruby, Rust, Vue, Svelte, Astro |
| Ansible, Bash, C, C++, C#, Dart, Elixir, HCL and Terraform, Julia, Kotlin, Lua, Luau, Nix, Objective-C, PHP, PowerShell, Scala, Solidity, SQL, Swift, Verilog, Zig, Zsh |
| R, GDScript, ReScript, VB.NET, Perl |
none needed | Perl XS |
Parse accuracy is measured per language against two labelled samples and published in docs/BENCHMARKS.md. A language whose optional grammar is not installed is reported as not measured, never scored zero.
Perl XS is read differently, and labelled differently. No permissive grammar for .xs files exists anywhere this project can reach, so no extra changes how it is read:
Aspect | How Perl XS is handled |
How it is read | A documented pattern extractor, never a full parse |
How it is reported |
|
Effect on results | Every connection leaving such a file is scaled down in confidence |
Measured accuracy | Precision 0.875 and recall 0.7778 on the held-out sample |
Install
Requirements. Python 3.10 or newer. The core install pulls no runtime dependencies. macOS and Linux are the tested targets.
# from a clone of the repository
python3 -m venv .venv
./.venv/bin/python -m pip install --upgrade pip
./.venv/bin/python -m pip install -e ".[dev]"
./.venv/bin/dkg --version # dkg 0.1.0Add optional extras only when you need them, for example pip install -e ".[embeddings,reranker,code]". Every optional component reports the exact reason when it is unavailable.
Quick start
dkg init # create a project-local .dkg home
dkg ingest ./my-notes --recursive # ingest text, markdown, json, csv, docx
dkg status # print counts and configuration
dkg search "confidence formula" # keyword, fts, or hybrid (default hybrid)
dkg graph "beta" --depth 2 # bounded graph neighbourhood
dkg evidence <claim-id> # evidence packet for a claim
dkg community # group the graph with both detectors
dkg code-ingest ./my-repo # parse a repository into the code graph
dkg code-hubs # most connected symbols and chokepoints
dkg code-gaps # isolated symbols and untested hotspots
dkg code-questions # review questions generated from the graph
dkg code-architecture # component overview with coupling warnings
dkg graph-snapshot before.json # snapshot now, diff later with graph-diff
dkg export --format html --out graph.html # offline viewer, or json / csv / dot / cypher / obsidian
dkg audit --verify # verify the audit log
dkg mcp-stdio # start the read-only assistant serverIf you are new to the command line
Install Python 3.10 or newer from python.org, then open a terminal in the project folder.
Copy the four install commands above one line at a time. The last line should print
dkg 0.1.0.Run
dkg init, thendkg ingestpointed at a folder of your notes, thendkg search "a phrase you expect to find".
Every command prints readable text by default and machine-readable JSON with --json. No step contacts the network unless you pass --allow-network.
One install, every supported platform
The same install path everywhere, because the core is standard library only. There is no wheel to match to your operating system, no compiler step, and no service to run.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#e4e4e4","primaryTextColor":"#404040","primaryBorderColor":"#a5a5a5","lineColor":"#757575","secondaryColor":"#d4d4d4","tertiaryColor":"#f4f4f4","clusterBkg":"#f4f4f4","clusterBorder":"#a5a5a5","edgeLabelBackground":"#f4f4f4","textColor":"#404040"}}}%%
flowchart TB
py["Python 3.10 or newer"]
install["pip install -e ."]
py --> install
subgraph tested["Tested here"]
direction LR
mac["macOS"]
linux["Linux"]
end
subgraph untested["Not verified on this host"]
direction LR
win["Windows<br/>stdlib and pathlib throughout,<br/>never run on a Windows machine"]
cont["Docker and Podman<br/>files ship, container runtime<br/>not driven here"]
end
install --> tested
install --> untested
tested --> same["One SQLite file.<br/>No service, no daemon required,<br/>no network."]
untested -.-> same
classDef inner fill:#e4e4e4,stroke:#a5a5a5,color:#404040
classDef strong fill:#d4d4d4,stroke:#757575,color:#282828
classDef outer fill:#f4f4f4,stroke:#a5a5a5,color:#404040
class py,install outer
class mac,linux inner
class win,cont outer
class same strongThe dotted line is there for a reason. macOS and Linux are the tested targets. Windows and the container images ship but have not been run on this machine, and this document says so rather than assuming the code is portable because it looks portable.
Connect an AI assistant
The assistant integration speaks the Model Context Protocol, or MCP: a standard, read-only connection an AI assistant can use to query your graph. It runs over standard input and output, with an optional local-only HTTP surface that requires a token and checks the request origin.
Only query tools are registered. No tool that writes is ever exposed, so an assistant acting on content it was fed cannot change your graph through this connection.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#e4e4e4","primaryTextColor":"#404040","primaryBorderColor":"#a5a5a5","lineColor":"#757575","secondaryColor":"#d4d4d4","tertiaryColor":"#f4f4f4","clusterBkg":"#f4f4f4","clusterBorder":"#a5a5a5","edgeLabelBackground":"#f4f4f4","textColor":"#404040"}}}%%
flowchart LR
asst["Your assistant<br/>any model, any vendor"]
asst -->|"JSON-RPC over stdio"| srv["dkg mcp-stdio<br/>read-only tool surface"]
subgraph guards["Enforced outside the model"]
direction TB
g1["Query tools only<br/>no write tool registered"]
g2["Path reads confined to a root<br/>and size-capped"]
g3["Node and edge reads bounded together,<br/>truncation reported"]
g4["Fetched content labelled<br/>untrusted evidence, never instructions"]
end
srv --> guards
guards --> db[("Local SQLite graph<br/>opened read-only")]
db --> ans["Answer with provenance,<br/>confidence, and the source it came from"]
ans --> asst
classDef inner fill:#e4e4e4,stroke:#a5a5a5,color:#404040
classDef strong fill:#d4d4d4,stroke:#757575,color:#282828
classDef outer fill:#f4f4f4,stroke:#a5a5a5,color:#404040
class asst outer
class g1,g2,g3,g4 inner
class srv,ans inner
class db strongSet up an editor with dkg mcp-install --client <name>, preview it with --dry-run, and undo it with dkg mcp-uninstall, which removes only what it wrote. Run dkg mcp-tools to list the editors it can configure. Parameters for every tool are in docs/COMMANDS.md.
The tool surface
Tool | What it returns |
| Database counts and the application version. |
| A compact orientation for an unfamiliar graph: its shape, its largest components, and where to start. |
| Hybrid search over chunks, fusing keyword and FTS5 and reporting which engines contributed. |
| Keyword search over chunks. |
| FTS5 search over chunks. |
| The bounded graph neighbourhood around an entity. |
| Communities over the entity graph by modularity optimization. |
| The same, then splits any community larger than a threshold. |
| Compares two code-graph snapshots written by |
| The evidence packet for one claim, with its explainable confidence. |
| Every source with its per-source chunk count. |
| Every language the plane parses, how each is read, and whether it is available here. |
| Parses one source file and returns its symbols, without writing to the database. |
| Search over code symbols and code text. |
| Structural blast-radius for a symbol or file. Over-approximate and advisory. |
| Blast radius with each impacted symbol given its own reason and distance. |
| Structural execution-flow trace, forward call chains from an entry symbol. |
| The catalogued execution flows in ranked order. |
| One catalogued flow by name or identifier, with its steps. |
| Which catalogued flows pass through a changed file set. |
| Symbols that call the named one, as node-level slices rather than whole files. |
| Symbols the named one calls, as node-level slices. |
| Symbols related in either direction, across calls, imports, and inheritance. |
| Modules that import the named module, each with its edge confidence. |
| Types the named type inherits from, each with its edge confidence. |
| Types that inherit from the named type, each with its edge confidence. |
| Tests that exercise the named symbol, each with its edge confidence. |
| The most connected symbols and the architectural chokepoints. |
| Edges that are surprising given the surrounding structure. |
| Isolated symbols, untested hotspots, and thin communities. |
| Review questions generated from the graph, each naming the measurement that prompted it. |
| A component-level map with coupling warnings. |
| Precomputed per-community summaries: members, files, and internal structure. |
| A structural summary of the repository the server is confined to. |
| Everything a reviewer needs about one symbol, in a single call. |
| Every execution flow from an entry point, scored by weighted criticality. |
| An advisory risk score in 0 to 1 for a change set. |
| The precomputed per-symbol structural risk index, highest first. |
| The three-tier confidence profile of the code graph. |
| Candidate dead code: definitions with no inbound reference edge. |
| Symbols whose recorded line span is at least a given size. |
| Refactoring suggestions derived from the community structure. |
| A symbol rename as a read-only edit list. It previews; it never writes. |
| Answer-shaped node-level slices for one structural question. |
| Free-form traversal from any node, breadth-first or depth-first. |
| Framework relations for a symbol: |
| Every registered repository with its per-repository status. |
| Search across every registered repository, with per-repository results. |
| The recorded answers held in the memory loop. |
| The reusable prompt templates for the recurring review tasks. |
| One reusable prompt template by name. |
| A named section of the shipped documentation, confined to the docs root. |
Every one of these reads. None of them writes. The setup helper that does write files is available on the command line only and is kept off this surface on purpose.
Continuous integration
A ready-made GitHub Action runs the analysis on a repository and posts a risk-scored review as a single pull-request comment, updating that same comment on every push rather than adding a new one. Copy this into .github/workflows/:
name: code-review
on:
pull_request:
branches: ["**"]
permissions:
contents: read
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
fetch-depth: 0 # the base ref must be diffable
persist-credentials: false
- uses: scorpion1476-lgtm/D-Knowledge_Graph@v0.1.0
with:
repository-path: "."
base-ref: ${{ github.event.pull_request.base.sha }}
# Pin the analysed tool, not just the action. A floating ref here
# would silently change what runs against your code.
dkg-ref: "v0.1.0"
dkg-repo-url: "https://github.com/scorpion1476-lgtm/D-Knowledge_Graph.git"
comment: "true"
pr-number: ${{ github.event.pull_request.number }}
github-token: ${{ secrets.GITHUB_TOKEN }}
# Off by default. Set to low, moderate, elevated, or high to gate.
# Thresholds derive from your repository's own score distribution.
risk-gate: "off"The single-workflow form above runs pull-request code in a job that holds a write token. That is safe where only trusted contributors open pull requests.If you accept pull requests from forks, use the two-stage form instead: one workflow renders the review with no write permission and no secret, and a second posts it from a job that never checks out the pull request's code. Both files ship in this repository.
The action's inputs, outputs, and risk model are documented in docs/CONSUMER_ACTION.md. It installs the tool from a pinned version, pins its own sub-actions to exact commits, and needs no service and no account.
Security
The platform is secure by default. Each control below is implemented in the source and covered by a test.
Control | Default | Detail |
Outbound network | Off | Reaching out needs an explicit |
Telemetry | None | There is nothing to switch off; it can only ever be switched on deliberately. |
Assistant connection | Read-only | Only query tools exist. The HTTP option binds to your own machine, needs a token, and caps request size and rate. |
Request forgery | Blocked | Addresses are checked after resolution, and private, loopback, and cloud-metadata addresses are refused before any fetch. |
Secret redaction | On | Logs, audit lines, and exports pass through a redactor that masks keys, tokens, and private-key blocks. |
Untrusted content | Enforced | Fetched web content is labelled as evidence, never as instructions, and is scored for injection attempts. |
Storage | Parameter-bound | Every database query is parameterized; the storage layer refuses string-built queries. |
Provenance and evidence | Always on | Every record records where it came from, and the audit log is append-only with a per-row hash chain. |
Supply chain | Hardened | Actions are pinned to exact commits, dependencies are pinned with a generated lockfile and bill of materials, and licence and vulnerability scans run in CI. |
The full model, including what is deliberately out of scope, is in docs/SECURITY_MODEL.md and docs/THREAT_MODEL.md.
Benchmarks
Accuracy here is measured rather than asserted. Every figure comes from a documented sample with a fixed seed, and one command regenerates all of them:
python scripts/benchmark.pyWhat is measured | Sample | Result |
Search quality | 30 documents, 40 queries | Keyword alone scores MRR 0.9375 and nDCG@10 0.9473. With the optional embedding model and reranker, both reach 1.0. |
Change-impact precision | 42 evaluation nodes, 24 true edges per language | Precision 0.1081 by default and 1.0 with |
Code parse accuracy | 113 symbols across 13 languages, labelled before ever being parsed | Precision 0.982 and recall 0.9646. |
Grouping quality | 80 entities in 16 groups, and 40 entities in 5 topics | The two detectors tie on structure at Rand 1.0. Where meaning matters, the refinement leads at Rand 0.7641 against 0.641. |
Execution-flow accuracy | Hand-labelled call graphs per language | Precision and recall 1.0 for Python, JavaScript, and Go. |
Contradiction detection | 18 held-out cases | Recall 0.6667 and precision 0.75. Advisory, and lexical rather than reasoning. |
Media accuracy | Rendered samples, not natural photographs | OCR character and word error rate 0.0, and image tagging top-1 0.9375. |
Two things this page will not claim. The graph route is a correctness result rather than a saving: against a capable search-and-read baseline it uses roughly twice the tokens, 71,088 against 34,744, while scoring 1.0 mean correctness against 0.6206. And a benchmark whose optional tool or model is not installed is reported as not run here, never as a zero and never as a pass.
Full results, sample sizes, methodology, and the limitations of each sample are in docs/BENCHMARKS.md.
Use cases
The platform is a private, checkable research and knowledge substrate. Because it runs offline and records the origin of every record, it fits work where the source of an answer matters as much as the answer.
Team or role | What they use it for | Outcome |
Research and analysis | Ingest notes, reports, and feeds, then search, traverse, and cross-check claims against their sources. | A searchable graph where every claim links back to its document. |
Compliance and legal review | Keep sensitive material on a local or disconnected machine and produce evidence with a readable confidence. | A defensible offline record of what was found and where. |
Knowledge management | Turn scattered files into a connected graph, group related material, and export it to Obsidian or Graphviz. | A maintained map of your own knowledge, with nothing locked in. |
Investigation and due diligence | Surface contradictions across sources and follow bounded queries between entities. | A reviewable map of where sources agree and disagree. |
Run a deterministic agent workflow over the graph with no model connected at all, then register a local model behind the adapter interface when you want higher recall:
dkg agent research --input '{"query":"knowledge graph"}'
dkg agent contradiction --input '{}'
dkg agent security-review --input '{"limit":500}'For engineering teams
Engineering use case | How the platform serves it |
Code intelligence | Parse a repository into a code graph and query symbols, call structure, and execution flow from an entry point. |
Architecture review | Surface the most connected symbols, the points whose removal splits the graph, cycles between components, and connections that cross a boundary. |
Reviewing an unfamiliar change | Generate review questions from the graph, each naming a symbol and the measurement behind it, then diff two snapshots to see what moved. |
Change-impact review | Compute an advisory impact set for the changed files, with an opt-in gate for CI, through the GitHub Action or |
Offline knowledge graphs | Build and browse a graph in a self-contained HTML viewer that loads nothing from the network. |
Air-gapped deployments | Install from source with no runtime dependencies and run every core capability with the network off. |
Change impact and execution flow over-report by design in the default path. The optional --resolve path narrows ambiguous calls with type-aware resolution wherever a language server is installed.
FAQ
The short answers. The longer ones, including honest comparisons against a language server, similarity search, and plain text search, are in docs/FAQ.md.
Question | Answer |
Is this open source? | No. It is source-available and non-commercial. Commercial use, modification, and modified redistribution are all prohibited. See the licence section below. |
Does it replace a language server? | No, and it uses one when one is installed. The default code path over-reports; |
Does it replace text search? | No. For "where does this exact string appear", plain search wins and nothing here beats it. The graph is for questions that are not strings. |
Does it replace a vector database? | No. It includes similarity search as an option and adds structure, evidence, and a record of where everything came from. For plain semantic search over text, a vector database is simpler. |
Does it phone home? | No. There is no telemetry, and reaching out needs an explicit |
Does it download models? | Never while running. Models are placed on disk ahead of time and loaded from local files only; an absent model steps aside to a documented fallback. |
How do I know it installed correctly? |
|
How do I tell an install problem from an environment problem? |
|
When should I not use it? | When you need certainty rather than an advisory result, when your collection is enormous, when you need a hosted service, or when you need commercial use. |
Troubleshooting
Every entry in docs/TROUBLESHOOTING.md carries a symptom, a cause, and a fix, across install and path problems, server start-up failures, database locking and staleness, missing optional components, and the Windows and Linux-subsystem issues. The Windows entries are marked as inferred from the code rather than observed, because no Windows machine was used.
Two commands answer most problems before you read anything:
dkg doctor # the application's self-check, as JSON
python scripts/probe_environment.py # the environment around it, as JSONPaste both into a bug report. The second one's package-index check is the only outbound request it can make, it names the address in its own output, and --offline skips it.
Documentation
Document | What is in it |
The shortest path to a working graph. | |
Worked workflows for research, verification, contradiction, export, backup, and restore. | |
Every subcommand and every assistant tool, with parameters and defaults. | |
The base grouping detector, in plain language and in full technical detail. | |
The refinement detector, in plain language and in full technical detail. | |
Every measured number, with sample sizes and the seed. | |
Every parsed language, its extensions, how it is read, and its grammar licence. | |
Honest comparisons, what it does not replace, and how to verify an install. | |
Symptom, cause, and fix for the problems that actually happen. | |
Running an installation: homes, backups, retention, and the audit log. | |
Local, container, and self-hosted deployment, with reverse proxy and TLS. | |
Repository layout, local development, the test suite, and how to add a command or adapter. | |
How the core and the two planes fit together. | |
The GitHub Action: inputs, outputs, the risk model, and the fork-safe form. | |
The controls, and the adversaries they are for. | |
Shipped, in progress, planned, and not planned. | |
Development in a clone, the gate commands, and what a change must satisfy. | |
Supported versions, the private reporting channel, and response timelines. | |
The standard, its scope, and how to report a concern. |
Licence
Source-available and free for personal and non-commercial use. This is not an open-source licence: commercial use is not permitted, and neither is modification or distributing a modified version.
Component | Licence | Terms |
The entire repository, Ariadne included | D-Knowledge Graph Source-Available Non-Commercial Licence (PolyForm Noncommercial 1.0.0 plus a no-modification term) | Read, run, and use the output for any non-commercial purpose. Redistribute verbatim copies with |
Optional third-party dependencies | Their own permissive licences (Apache-2.0, MIT, BSD, ISC, HPND) | Unaffected by the terms above. Full inventory in |
One licence covers everything. There is no separately licensed module and no component excluded from the build. The default runtime uses only the Python standard library and copies no source from any other project.
Versions distributed before 2026-08-05 were released under Apache-2.0. That grant remains in force for those versions and for anyone who received a copy under it; these terms govern this version onward. See LICENSE and NOTICE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseBqualityCmaintenanceA local-first MCP server that provides AI agents with safe codebase access through file discovery, hybrid lexical-semantic search, and project introspection. It features durable local memory and semantic indexing while keeping all data and processing entirely on your local machine.74836MIT
- AlicenseAqualityDmaintenanceLocal-first RAG indexing and semantic search MCP server. Enables document retrieval and context-aware queries using local embedding models.314MIT
- AlicenseNot gradedqualityDmaintenanceLocal MCP server for indexing personal knowledge into SQLite with hybrid search, chunk-level citations, memory tools, and agent orchestration.4MIT
- FlicenseAqualityCmaintenanceA local-first MCP server providing secure workspace file operations, offline full-text search, and web search/fetch capabilities without requiring API keys.10
Related MCP Connectors
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
Private-by-default, local-first memory/context/task orchestrator for MCP apps and agents.
Markdown-based note-taking with a hosted MCP server. Your notes serve you and your AI.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/scorpion1476-lgtm/D-Knowledge_Graph'
If you have feedback or need assistance with the MCP directory API, please join our Discord server