# myKG — The Knowledge Graph Engine [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/) [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE) [![CI](https://github.com/SenolIsci/mykg/actions/workflows/ci.yml/badge.svg)](https://github.com/SenolIsci/mykg/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/SenolIsci/mykg/branch/main/graph/badge.svg)](https://codecov.io/gh/SenolIsci/mykg) [![Providers](https://img.shields.io/badge/LLM-Anthropic%20%7C%20OpenAI%20%7C%20Gemini%20%7C%20Ollama%20%7C%20OpenRouter-orange.svg)](#configuration) [![Agent](https://img.shields.io/badge/Agent-Claude%20Code-green.svg)](docs/agent-mode.md) [![PyPI version](https://img.shields.io/pypi/v/mykg.svg)](https://pypi.org/project/mykg/) [![Downloads](https://img.shields.io/pepy/dt/mykg?color=blue&label=downloads)](https://pepy.tech/project/mykg) [![GitHub Stars](https://img.shields.io/github/stars/SenolIsci/mykg?style=flat-square&logo=github)](https://github.com/SenolIsci/mykg/stargazers) [![GitHub Issues](https://img.shields.io/github/issues/SenolIsci/mykg.svg)](https://github.com/SenolIsci/mykg/issues) [![Visitors](https://visitor-badge.laobi.icu/badge?page_id=SenolIsci.mykg)](https://github.com/SenolIsci/mykg) [![Medium](https://img.shields.io/badge/Medium-000000?logo=medium&logoColor=white)](https://medium.com/@senol.isci) [![LinkedIn](https://img.shields.io/badge/LinkedIn-senolisci-0077B5?logo=linkedin)](https://www.linkedin.com/in/senolisci/) **myKG** automatically generates a confidence-scored knowledge graph from a set of mixed documents — Markdown, plain text, PDF, Word, PowerPoint, Excel, HTML, and images — grounded in an induced RDFS/OWL ontology.

## Updates - **v0.4.10** — Schema drift detection and pruning: `mykg detect-schema-drift` reports concepts and properties the graph no longer uses, and `mykg prune-schema` removes them (with `--preview`, an editable plan file, and a backup). See [Schema Drift & Pruning](#schema-drift--pruning). - **v0.4.9** — The `nodes.jsonl`, `edges.jsonl` and `knowledge_graph.ttl` exports now stream to disk record by record instead of building the whole file in memory first, so peak memory stays flat as the graph grows. - **v0.4.8** — `mykg_search_nodes` and `mykg_query_graph`'s seed selection now use BM25 instead of a linear substring scan, ~2,800x faster at 100K nodes (0.5ms vs. 1.4s per query) and no longer degrading to minutes per query as the graph grows. ## Contents - [Features](#features) - [Quick Start](#quick-start) - [Command line](#command-line) - [Articles & Tutorials](#articles--tutorials) - [Configuration](#configuration) - [Extract Pipeline](#extract-pipeline) - [Running](#running) - [Sessions](#sessions) - [Pipeline Steps](#pipeline-steps) - [Outputs](#outputs) - [MCP (Model Context Protocol) Server](#mcp-model-context-protocol-server) - [Using mykg with Claude Code](#using-mykg-with-claude-code) - [Agent mode (Claude Code skill)](#agent-mode-claude-code-skill) - [claude-cli profile](#claude-cli-profile) - [Advanced Options](#advanced-options) - [Re-running from a Specific Step](#re-running-from-a-specific-step) - [Orphan-Connection Pass](#orphan-connection-pass) - [Human Review Gate](#human-review-gate---review) - [Locked Base Schema](#locked-base-schema---base-schema) - [SKOS Thesaurus](#skos-thesaurus---thesaurus) - [Website / Repo Fetching](#website--repo-fetching-mykg-fetch-web) - [Standalone Document Conversion](#standalone-document-conversion-mykg-parse-docs) - [Append Mode](#append-mode) - [Incremental Schema Growth](#incremental-schema-growth---append-with-grow-schema) - [Merging Sessions](#merging-sessions) - [Walkthrough Report](#walkthrough-report) - [Schema Drift & Pruning](#schema-drift--pruning) - [Obsidian Vault Export](#obsidian-vault-export) - [Neo4j Load CSV Export](#neo4j-load-csv-export) - [Troubleshooting](#troubleshooting) - [Roadmap](#roadmap) - [Development](#development) - [Testing](#testing) - [Healthiness check](#healthiness-check) - [Design](#design) - [License](#license) ## Features MyKG builds trustworthy knowledge graphs through a self-evolving ontology that continuously adapts, maintains consistency, and assigns confidence scores to knowledge, keeping information grounded and reliable as it grows. ### Ontology-Guided Extraction - **Schema-guided knowledge graph generation** — the extracted graph is always grounded in a formal RDFS/OWL schema: concept types, property names, domain/range constraints, and the is-a hierarchy are explicit and inspectable before any entity is extracted - **AI coding assistant friendly** — designed for smooth use alongside AI coding assistants such as [Claude Code](https://claude.ai/code); Use the Claude Code Skill to run extractions, inspect outputs, and iterate on your knowledge graph without leaving your coding environment; see [Using mykg with Claude Code](#using-mykg-with-claude-code) - **Second brain for AI coding assistants** — the Obsidian vault output turns your extracted knowledge graph into a directory of wikilinked Markdown notes that any AI coding assistant can read as project context; point Claude Code, Cursor, or Copilot at `output/obsidian_vault/` and ask questions, trace relationships, and get answers grounded in your own documents - **MCP server for desktop AI apps** — run `mykg mcp-serve` to expose your knowledge graph via the [Model Context Protocol](https://modelcontextprotocol.io/); integrates with [Claude Desktop](https://claude.ai/download), [Cherry Studio](https://cherry-ai.com), and any MCP-compatible client — 16 query tools let LLMs search entities, explore relationships, find paths, traverse the graph, and read wiki notes directly from your extracted knowledge; see [MCP Server](#mcp-model-context-protocol-server) - **Incremental updates** — append new files to an existing session, extracting only what changed. Optionally grow the schema from new documents while preserving existing concepts and properties - **Resumable pipeline** — every stage persists intermediate state; re-enter at any step after a crash or edit - **Session isolation** — each run is fully self-contained; inputs, intermediate state, outputs, and logs co-located - **Cross-session merge** — combine two independently-produced graphs into one unified knowledge graph - **Bring your own ontology** — supply a `--base-schema` TTL file (RDFS or OWL) to lock in classes and properties from an existing formal ontology; the LLM expands it with domain-specific concepts but will not rename, remove, or contradict your authoritative vocabulary. Please note that this mechanism is controlled by the LLM, and may not be strictly enforced. Add `--freeze-schema` to skip LLM schema induction entirely and extract from the documents strictly against your ontology verbatim — no surprise types, no invented properties - **SKOS thesaurus support** — pass `--thesaurus` to load a SKOS vocabulary; `skos:exactMatch` terms are collapsed silently, `skos:closeMatch` terms trigger a warning — giving the schema merger richer synonym awareness than string matching alone - **Verifiable TTL ontology** — after Pass 1, the induced schema is exported as a valid RDFS/OWL Turtle file (`intermediate/schema.ttl`) that can be opened directly in ontology editors such as [Protégé](https://protege.stanford.edu/). The TTL is validated by rdflib (syntax + semantic checks: domain/range refer to declared classes, no conflicting ranges) before any extraction begins - **Human-in-the-loop ontology design** — pause after schema induction with `--review`, edit the schema, and resume extraction. Edit `schema.json` directly or refine `schema.ttl` in Protégé and feed it back with `--freeze-schema`

### Input - **Mixed-format corpora** — point `mykg extract-graph` at any directory; supported extensions are converted to Markdown automatically before ingest: | Format | Extensions | Backend | |---|---|---| | Markdown | `.md` | passthrough (consumed as-is) | | Plain text | `.txt` | renamed to `.md` in-process | | PDF, Word, PowerPoint, Excel, images | `.pdf .docx .doc .pptx .xlsx .png .jpg .jpeg` | [MinerU](https://github.com/opendatalab/mineru) in an ephemeral `uv`-managed Python 3.12 venv — nothing is installed into your active environment | | HTML | `.html .htm` | [`markdownify`](https://pypi.org/project/markdownify/) in-process; anchors and image tags stripped | | Websites, GitHub repos | any URL | [Crawlee](https://github.com/apify/crawlee) in an ephemeral `uv` venv — produces an `mykg_web_fetch/` folder Anything outside the allowlist (e.g. `.svg`, `.css`, `.php` assets next to an HTML bundle) is logged and skipped, never silently dropped. The allowlist is configurable via `preprocess.extensions` in `mykg_config.yaml`. **Incremental conversion** — unchanged source files are skipped on re-run. Adding one PDF to a corpus and re-running only re-converts that PDF. Force a full re-conversion with `mykg extract-graph --from-step preprocess`. ### Graph & Output - **Provider-agnostic** — works with Anthropic (Claude), OpenAI (GPT), Google Gemini, Ollama (local), OpenRouter, or the `claude` CLI - **Five output families** — JSONL for Neo4j/NetworkX/RAG, Turtle RDF for OWL toolchains, NetworkX multi-format for graph analysis, Obsidian vault for linked personal knowledge management, and an optional Neo4j LOAD CSV bundle (plain-header CSVs + paste-and-run Cypher script for Neo4j Browser / `cypher-shell`) - **Obsidian vault — second brain for AI coding assistants** — every extracted entity becomes a wikilinked Markdown note in `output/obsidian_vault/`; open it in [Obsidian](https://obsidian.md) to navigate the graph with backlinks and Graph View, or point your AI coding assistant (Claude Code, Cursor, Copilot) at the vault folder so it can answer questions, trace relationships, and reason over your knowledge base in natural language - **Interactive HTML graph** — node/edge filtering, search, hover popups; opens directly in a browser - **Confidence scoring** — every extracted attribute, node, and edge carries a `0.0–1.0` confidence score ## Quick Start Requires Python 3.11+ (developed on macOS; automated CI runs the test suite on Ubuntu and Windows), and one of: an Anthropic/OpenAI/Gemini/OpenRouter API key, Ollama running locally, or the `claude` CLI. ### Install from PyPI Install mykg, then run the interactive setup wizard — it asks for your provider, model, and API key and writes `mykg_config.yaml` and `.env.mykg` in one step. ```bash pip install mykg mykg init ``` Then extract a knowledge graph from your notes: ```bash mykg extract-graph my_notes/ ``` Open `mykg_sessions//output/knowledge_graph.html` in your browser to explore the result. ### Install from source Install [uv](https://docs.astral.sh/uv/getting-started/installation/), clone the repo, sync dependencies, run the setup wizard, then extract. ```bash git clone https://github.com/SenolIsci/mykg && cd mykg uv sync && uv run mykg init --force ``` Then extract a knowledge graph from your notes: ```bash uv run mykg extract-graph my_notes/ ``` For Ollama (local inference, no API key needed), pull a model and select the `ollama-local` profile when `mykg init` prompts you. ```bash ollama pull llama3.3 mykg init mykg extract-graph my_notes/ ``` ## Command line ### All Commands | Command | Purpose | |---|---| | [`mykg init`](#configuration) | Interactive setup wizard — writes `mykg_config.yaml` and `.env.mykg` | | [`mykg extract-graph`](#extract-pipeline) | Run the two-pass extraction pipeline over a directory | | [`mykg query ""`](#terminal-query-mykg-query) | Query the knowledge graph from the terminal — BFS/DFS traversal from seed nodes matching your question; mirrors the MCP query tool | | [`mykg walkthrough`](#walkthrough-report) | Regenerate `walkthrough.md` for an existing session | | [`mykg detect-schema-drift`](#schema-drift--pruning) | Report schema concepts/properties with no instances in the graph (read-only, no LLM) | | [`mykg prune-schema`](#schema-drift--pruning) | Remove unused concepts/properties from the session schema; `--preview` shows the plan, `--plan ` applies an edited one (no LLM) | | [`mykg merge-graphs`](#merging-sessions) | Merge two independently-produced sessions into one unified graph | | [`mykg parse-docs`](#standalone-document-conversion-mykg-parse-docs) | Standalone MinerU/markdownify document-to-Markdown conversion | | [`mykg fetch-web`](#website--repo-fetching-mykg-fetch-web) | Crawl a website or clone a GitHub repo into an `extract-graph`-ready folder | | [`mykg mcp-serve`](#mcp-model-context-protocol-server) | Start the MCP server exposing read-only graph query tools | | `mykg approve-schema` | Write `schema_approved.flag` to unblock the `human_review` gate after editing `schema.json` (used with `--review`, see [Human Review Gate](#human-review-gate---review)) | ``` mykg extract-graph my_notes/ # any directory: .md, .txt, .pdf, .docx, .html, images ``` It uses a **two-pass LLM pipeline**: Pass 1 induces a global RDFS/OWL schema from your document corpus; Pass 2 extracts typed entity and relationship instances per file against that schema. Non-Markdown inputs (`.txt .pdf .docx .doc .pptx .xlsx .png .jpg .jpeg .html .htm`) are converted to Markdown automatically before extraction. The result is exported to multiple formats: JSONL for property-graph consumers such as Neo4j, Turtle RDF for OWL toolchains, seven NetworkX formats for graph analysis and visualization, an Obsidian vault — a second brain of wikilinked Markdown notes your AI coding assistant (Claude Code, Cursor, Copilot) can read and reason over directly — and optionally a Neo4j LOAD CSV bundle with a paste-and-run Cypher script for one-step import into Neo4j Browser or `cypher-shell`. ## Articles & Tutorials Walkthroughs and case studies on [Medium](https://medium.com/@senol.isci): - [How I Turned My Website Into a Knowledge Graph with myKG](https://medium.com/@senol.isci/how-i-turned-my-website-into-a-knowledge-graph-with-mykg-7dc85ac894c3) - [How to Build a Second Brain You Can Actually Trust](https://medium.com/@senol.isci/how-to-build-a-second-brain-you-can-actually-trust-52ac621188b7) - [Build an LLM Wiki for Your AI Agents](https://medium.com/@senol.isci/build-an-llm-wiki-for-your-ai-agents-b993af38d7c4) - [From Documents to a Living Knowledge Graph: Introducing myKG](https://medium.com/@senol.isci/from-documents-to-a-living-knowledge-graph-introducing-mykg-fab7cea22de5) ## Configuration All configuration lives in a single `mykg_config.yaml` file discovered automatically from the working directory (or any parent). There are no hardcoded defaults in the code — the YAML is the sole source of truth. ```bash mykg init # interactive: choose provider, model, paste API key # writes mykg_config.yaml and .env.mykg in one step mykg init --force # overwrite an existing config mykg init --profile openrouter-free --model google/llama-4-maverick --api-key sk-or-... # non-interactive ``` The wizard walks you through three prompts: 1. **Profile** — choose your LLM provider (OpenRouter, Anthropic, OpenAI, Gemini, Ollama, Claude CLI, or Agent / Claude Code skill) 2. **Model** — accept the default or type any model slug for that provider *(skipped in agent mode — the host Claude Code session is the LLM)* 3. **API key** — paste your key (skipped for Ollama, Claude CLI, and agent mode) ### LLM Providers | Provider | Profile name | API key env var | Notes | |---|---|---|---| | Anthropic (Claude) | `anthropic-claude` | `ANTHROPIC_API_KEY` | Recommended for quality | | OpenAI | `openai` | `OPENAI_API_KEY` | | | Google Gemini | `gemini` | `GEMINI_API_KEY` | Implicit prompt caching is automatic. Profile ships the same token budgets as `openai`; raise `llm.context_window` to use Gemini's full 1M window | | Ollama | `ollama-local` | — | Local inference, no key needed | | OpenRouter | `openrouter-free` | `OPENROUTER_API_KEY` | Access many models via one key | | Claude CLI | `claude-cli` | — | Uses `claude -p` subprocess; serial only | | Agent (Claude Code skill) | `agent-claude-code` | — | LLM answers come from a Claude Code skill via filesystem inbox/outbox — see [docs/agent-mode.md](docs/agent-mode.md) | Switch provider by setting `profile:` at the top of [`mykg_config.yaml`](mykg_config.yaml). ### API Keys myKG reads API keys from environment variables. Set them by exporting directly or by creating a `.env.mykg` file in your project directory (loaded automatically on startup). **Option A — export in your shell:** ```bash export ANTHROPIC_API_KEY=sk-ant-... ``` **Option B — create a `.env.mykg` file:** ```bash # .env.mykg ANTHROPIC_API_KEY=sk-ant-... ``` For source installs you can also copy [`sample.env.mykg`](sample.env.mykg) to `.env.mykg` as a starting template. ## Extract Pipeline Reads a directory of mixed format files and produces a typed knowledge graph in three output formats. The pipeline runs 12 sequential steps; all intermediate state is persisted so any step can be re-entered without repeating upstream work. ### Running ```bash mykg extract-graph [OPTIONS] # source installs: uv run mykg extract-graph [OPTIONS] ``` `` is any directory containing your source files. Subdirectories are included recursively. Only files matching the configured extensions are copied into the session: - `.md` — always included (the pipeline's native format) - All extensions listed under `preprocess.extensions` in `mykg_config.yaml` (`.pdf`, `.docx`, `.doc`, `.pptx`, `.xlsx`, `.png`, `.jpg`, `.jpeg`, `.html`, `.htm`, `.txt` by default) Everything else (`.py`, `.json`, `.yaml`, lock files, etc.) is ignored. Hidden directories (`.venv`, `.git`, etc.) and the sessions folder are also excluded automatically, so you can safely point `extract-graph` at the project root or any parent directory. ### Options | Option | Description | |---|---| | `--session NAME` | Resume an existing session by folder name | | `--from-step NAME` | Delete a step's outputs and re-run from that point | | `--review` | Pause after Pass 1 for manual schema review | | `--append` | Skip Pass 1; extract NEW files only. Modified and deleted files are detected and warned about — add `--sync` to act on them | | `--sync` | With `--append`: reconcile the graph against the folder — re-extract MODIFIED files and remove DELETED ones | | `--update` | Shorthand for `--append --sync` | | `--append-with-grow-schema` | Like `--append`, but runs a locked Pass 1 over changed files to expand the schema. Composes with `--sync` | | `--pass1-schema-induction-only` | Run every step before Pass 2 (through `schema_flatten`), then stop — inspect/edit the schema before extracting | | `--pass2-kg-extraction-only` | Skip schema induction (requires an existing schema) and extract the full corpus through `validate_graph`. Unlike `--from-step pass2`, always re-derives `flattened_schema.json` first, so a hand-edited schema is picked up | | `--profile NAME` | Use a different LLM profile from `mykg_config.yaml` for THIS run only (config file untouched; re-resolves provider/model/workers/timeouts from that profile) | | `--model NAME` | Override the model for this run. Requires `--profile` | | `--workers N` | Parallel workers for Pass 2 (default: `pass2.max_workers` from the active/selected profile) | | `--confidence-agg mean\|max` | Confidence aggregation when deduplicating | | `--base-schema PATH` | Locked TBox TTL file (locked classes/properties cannot be changed by the LLM) | | `--freeze-schema` | Use `--base-schema` verbatim: skip Pass 1 LLM induction entirely | | `--thesaurus PATH` | SKOS TTL thesaurus for synonym resolution in schema merge | | `--obsidian-vault` | Force Obsidian vault export for this run (overrides config) | | `--neo4j-csv` | Force Neo4j LOAD CSV bundle export for this run (overrides config) | | `--log-file PATH` | Write logs here (relative paths placed inside the session folder) | | `--verbose / -v` | Enable DEBUG-level logging | ### Examples ```bash # New run — auto-creates a timestamped session mykg extract-graph my_notes/ # Resume a session with 4 parallel Pass 2 workers mykg extract-graph my_notes/ --session 2026-05-17T18-31-07 --workers 4 # Run once against a different profile/model without editing mykg_config.yaml mykg extract-graph my_notes/ --profile openrouter-free --model google/llama-4-maverick # Pause for schema review after Pass 1 mykg extract-graph my_notes/ --review # → edit mykg_sessions//intermediate/schema.json mykg approve-schema --session 2026-05-17T18-31-07 mykg extract-graph my_notes/ --session 2026-05-17T18-31-07 --review # Re-run from assembly onward (reuses existing extractions) mykg extract-graph my_notes/ --session 2026-05-17T18-31-07 --from-step assemble # Lock a base ontology so the LLM won't rename its classes mykg extract-graph my_notes/ --base-schema ontology/core.ttl # Induce and inspect the schema first, extract in a second invocation mykg extract-graph my_notes/ --pass1-schema-induction-only # → review/edit mykg_sessions//intermediate/schema.json mykg extract-graph my_notes/ --session --pass2-kg-extraction-only # Mix models across phases: a strong model for schema induction, # a smaller/cheaper one for the laborious Pass 2 extraction mykg extract-graph my_notes/ --profile openrouter-free --model google/gemma-4-26b-a4b-it:free --pass1-schema-induction-only ``` **Per-run `--profile` / `--model` for phase-specific model selection.** Because `--profile` and `--model` override the run without touching `mykg_config.yaml`, you can pick a different model for each phase of a two-phase extraction. Schema induction (Pass 1) benefits from a strong reasoning model, while the laborious per-file Pass 2 extraction can run on a smaller, cheaper model — just change `--profile`/`--model` between the `--pass1-schema-induction-only` and `--pass2-kg-extraction-only` runs. ### Sessions Every run automatically creates an isolated session folder: ``` mykg_sessions/ 2026-05-17T18-31-07/ input/ ← archived copy of all input Markdown files intermediate/ ← all intermediate pipeline state output/ ← final outputs (JSONL, TTL, HTML, NetworkX) run.log ← log file walkthrough.md ← post-run report ``` Sessions are the primary unit of resumability. Pass `--session ` to resume from the last completed step. Pass `--from-step ` to force-restart from a specific point. The sessions root is configurable via `pipeline.paths.sessions_dir` (default: `mykg_sessions/` in the current directory). ### Pipeline Steps The pipeline runs 12 steps in sequence. All intermediate state is written to disk so any step can be re-entered without repeating upstream work. | # | Step | LLM | Key outputs | |---|---|---|---| | 1 | `preprocess` | — | `preprocess.done`, `preprocess_manifest.json`, files under `input/_preprocessed/` *(routes non-md inputs to MinerU, markdownify, or rename; no-op for pure Markdown corpora)* | | 2 | `ingest` | — | `file_manifest.json` | | 3 | `pass1` | ✓ (3 calls) | `schema.json`, `schema.ttl`, `schema_history/`, `pass1_batch_selection.json`, `pass1_batch_proposals/` | | 4 | `schema_validate` | — | `schema_validate.done` | | 5 | `human_review` | — | `schema_approved.flag` *(only with `--review`)* | | 6 | `schema_flatten` | — | `flattened_schema.json` | | 7 | `pass2` | ✓ | `raw_extractions.json`, `chunk_node_index.json` | | 8 | `normalize_names` | ✓ | `name_normalization.json` | | 9 | `assemble` | — | `edge_metadata.json`, `nodes.json`, `merge_log.json` | | 10 | `orphan_score` | — | `orphan_candidates.json` | | 11 | `orphan_connect` | ✓ | `orphan_connections.json`, `orphan_log.json` | | 12 | `validate_graph` | — | `nodes.jsonl`, `edges.jsonl`, `knowledge_graph.ttl`, `knowledge_graph.html`, `networkx_output/`, `obsidian_vault/`, `neo4j_csv/` *(optional)* | Pass 1 internally runs four sequential stages: parallel batch induction → algorithmic merge → harmonization LLM call → quality review LLM call. `pass1.max_schema_proposals` (default 50) caps the number of batches dispatched to the LLM; set to `-1` to dispatch all batches on large corpora. ## Outputs ### Property Graph (JSONL) **`nodes.jsonl`** — one JSON line per entity: ```json { "id": "person-alice", "type": "Person", "confidence": 0.94, "source_files": ["team.md"], "attributes": { "name": {"value": "Alice", "confidence": 1.0}, "email": {"value": "alice@acme.com", "confidence": 0.88} }, "aliases": ["Alice Smith", "A. Smith"] } ``` **`edges.jsonl`** — one JSON line per relationship: ```json { "id": "works_at-abc123", "type": "works_at", "from": "person-alice", "to": "org-acme-corp", "confidence": 0.96, "method": "llm_extraction", "attributes": { "role": {"value": "Engineer", "confidence": 0.91}, "start_date": {"value": null, "confidence": 0.0} } } ``` Missing attributes are never dropped — they are represented as `{"value": null, "confidence": 0.0}`. The `method` field distinguishes edges extracted by Pass 2 (`llm_extraction`) from edges inferred by the orphan pass (`orphan_inferred`). ### RDF / OWL (Turtle) **`knowledge_graph.ttl`** — pure RDFS/OWL triples, no edge metadata: ```turtle @prefix ex: . @prefix : . ex:Person a rdfs:Class . ex:works_at rdfs:domain ex:Person ; rdfs:range ex:Organization . :person-alice a ex:Person ; rdfs:label "Alice" . :person-alice ex:works_at :org-acme-corp . ``` Load in Protégé, query with SPARQL (Fuseki, GraphDB), or reason with HermiT/Pellet. ### Interactive HTML **`knowledge_graph.html`** — self-contained D3.js force-directed graph. Open in any browser, no server required. Supports: - Filter nodes and edges by type - Filter by confidence threshold - Search by name - Hover popups with full attribute values - Resizable sidebar Not written when the graph exceeds `export.html_max_nodes` nodes (default 5000; `-1` disables the ceiling) — rendering a graph that large would overwhelm vis.js in the browser. Every other output format is still written in full. The key is read from the active profile's `pipeline.export:` block but is not present in the shipped config; add it there to override. ### NetworkX Formats (`networkx_output/`) | File | Format | Best for | |---|---|---| | `knowledge_graph.graphml` | GraphML | yEd, Gephi, Cytoscape | | `knowledge_graph.gexf` | GEXF | Gephi native (rich metadata) | | `knowledge_graph.json` | JSON node-link | D3.js, Sigma.js, web apps | | `knowledge_graph.gml` | GML | Human-readable inspection | | `knowledge_graph.net` | Pajek | Network analysis | | `edges_nx.txt` | Edge list | Text pipelines | | `adjacency.txt` | Adjacency list | Topology consumers | Node/edge attributes are exported as `attr__value` / `attr__confidence` scalar pairs for GML compatibility. ### Obsidian Vault (`obsidian_vault/`) One `.md` note per extracted entity, grouped into subdirectories by concept type. Each note has YAML frontmatter (id, type, confidence, sources), an attributes section, outgoing and incoming wikilink relationship sections, and a source files list. An `index.md` at the vault root summarizes node counts per type with links to every entity. Open `output/obsidian_vault/` as a vault in [Obsidian](https://obsidian.md) to get Graph View, backlink navigation, and full-text search across the extracted entities. ### Neo4j LOAD CSV Bundle (`neo4j_csv/`) Optional, off by default. Enable with `--neo4j-csv` on the command line, or set `pipeline.export.neo4j_csv_enabled: true` in `mykg_config.yaml`. When enabled, `step_validate_graph` writes a self-contained Neo4j import bundle next to the other outputs: ``` output/neo4j_csv/ nodes_