trikedb 0.8.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
trikedb-0.8.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ryuto Yoda
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
trikedb-0.8.0/PKG-INFO ADDED
@@ -0,0 +1,260 @@
1
+ Metadata-Version: 2.4
2
+ Name: trikedb
3
+ Version: 0.8.0
4
+ Summary: The DuckDB of graph databases: a knowledge graph that lives in a single YAML file, queried with full SPARQL 1.1. Built for LLM agents.
5
+ Author: Ryuto Yoda
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/RyutoYoda/trikedb
8
+ Keywords: knowledge-graph,rdf,triple-store,yaml,llm,agents,ontology
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Database
14
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
+ Requires-Python: >=3.10
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: PyYAML>=6.0
19
+ Requires-Dist: rdflib>=7
20
+ Provides-Extra: mcp
21
+ Requires-Dist: mcp<2,>=1.2; extra == "mcp"
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=7; extra == "dev"
24
+ Requires-Dist: mcp<2,>=1.2; extra == "dev"
25
+ Dynamic: license-file
26
+
27
+ <p align="center">
28
+ <img src="docs/logo.svg" width="220" alt="trikedb — a triceratops whose three horns are the triple: subject, predicate, object">
29
+ </p>
30
+
31
+ # trikedb
32
+
33
+ **The DuckDB of graph databases.** You query it like a real triple store — full SPARQL 1.1, reads *and* writes. Underneath, it's a single YAML file. Built for LLM agents.
34
+
35
+ ```yaml
36
+ triples:
37
+ - {s: salesflow-crm, p: PROVIDES, o: crm-sync-job}
38
+ - {s: crm-sync-job, p: INGESTS_TO, o: RAW_CRM_CONTACTS, schedule: hourly}
39
+ - {s: LEGACY_DUMP, p: MIGRATED_TO, o: RAW_CRM_CONTACTS, deprecated: true}
40
+ ```
41
+
42
+ That file **is** the database. No server, no daemon, no cloud deployment. It diffs cleanly in git, survives in a repo next to your code, and — the part trikedb is actually designed around — **an LLM agent can `Read` it directly and reason over your domain without hallucinating entity names.**
43
+
44
+ ## Why
45
+
46
+ RDF graph databases are like Oracle: powerful, correct, and heavy. SPARQL endpoints, OWL reasoners, enterprise semantic layers — great at scale, overkill when what you need is a curated map of a few hundred facts that your AI agents (and teammates) can trust.
47
+
48
+ DuckDB proved the pattern: keep the *interface* of the big system (full SQL, in DuckDB's case) and shrink the *machinery* down to an embedded library over a file. trikedb applies the same move to RDF graph databases — the interface is real SPARQL 1.1 (rdflib's engine, not a homegrown subset), the storage is YAML you can read, diff, and commit:
49
+
50
+ | | A full triple-store deployment | trikedb |
51
+ |---|---|---|
52
+ | Storage | server / cloud service | one YAML file |
53
+ | Query | SPARQL 1.1 | SPARQL 1.1 (same language, rdflib engine) |
54
+ | Writes | SPARQL Update | SPARQL Update — persisted back to the YAML |
55
+ | Schema | OWL + reasoners | a list of allowed predicates |
56
+ | Agent integration | a service to operate | the agent reads the file, or `trikedb mcp` (stdio, embedded) |
57
+ | Setup time | an afternoon (or a sprint) | `pip install trikedb` |
58
+
59
+ If you need inference engines, named graphs, and multi-tenant governance, you want a full enterprise semantic platform. If you want a knowledge graph **today, in a file, in git** — that's trikedb. And because the storage maps cleanly onto RDF, graduating to a bigger system later is an export, not a rewrite: each team keeps its own YAML graph, and stitching them together (or migrating them wholesale) is just merging triples.
60
+
61
+ ### Curation-first, not extraction-first
62
+
63
+ Most "AI knowledge graph" tools use an LLM to extract triples from text. That's great for bootstrapping, but extracted graphs inherit hallucinations. trikedb takes the opposite stance: **the graph is curated data** (by humans, or by agents you supervise), the ontology constrains what can be said, and LLMs *consume* the graph rather than invent it. When an agent reads
64
+
65
+ ```yaml
66
+ - {s: crm-sync-job, p: INGESTS_TO, o: RAW_CRM_CONTACTS}
67
+ ```
68
+
69
+ there is no step where a table name can be made up.
70
+
71
+ ## Install
72
+
73
+ ```bash
74
+ pip install trikedb # library + CLI
75
+ pip install 'trikedb[mcp]' # + MCP server for AI agents
76
+ ```
77
+
78
+ ## Quickstart (Python)
79
+
80
+ ```python
81
+ from trikedb import TrikeDB
82
+
83
+ db = TrikeDB("pipeline.yaml", ontology={
84
+ "PROVIDES": "SaaS vendor -> ingestion job",
85
+ "INGESTS_TO": "ingestion job -> warehouse table",
86
+ "MIGRATED_TO": "deprecated table -> its replacement",
87
+ })
88
+
89
+ db.add("salesflow-crm", "PROVIDES", "crm-sync-job")
90
+ db.add("crm-sync-job", "INGESTS_TO", "RAW_CRM_CONTACTS", schedule="hourly")
91
+ db.add("crm-sync-job", "OWNS", "x") # OntologyError: predicate not declared
92
+
93
+ # Pattern matching — None is a wildcard, '*' globs
94
+ for t in db.triples(p="INGESTS_TO", o="RAW_*"):
95
+ print(t.s, "->", t.o, t.attrs)
96
+
97
+ # Multi-pattern queries with variable joins (zero dependencies)
98
+ db.query(["?vendor PROVIDES ?job", "?job INGESTS_TO ?table"])
99
+ # [{'vendor': 'salesflow-crm', 'job': 'crm-sync-job', 'table': 'RAW_CRM_CONTACTS'}]
100
+
101
+ # Or real SPARQL 1.1 — FILTER, OPTIONAL, aggregates, the lot.
102
+ # Delegated to rdflib, not hand-rolled. The prefix t: is pre-bound.
103
+ db.sparql("""
104
+ SELECT ?vendor ?table WHERE {
105
+ ?vendor t:PROVIDES ?job .
106
+ ?job t:INGESTS_TO ?table .
107
+ FILTER(STRSTARTS(STR(?table), "urn:trikedb:RAW_"))
108
+ }
109
+ """)
110
+ db.sparql("ASK { ?x t:MIGRATED_TO ?y }") # True
111
+
112
+ # Writes go through SPARQL too, DuckDB-style — and land back in the YAML
113
+ db.sparql("INSERT DATA { t:figly t:PROVIDES t:figly-export-job }")
114
+ db.sparql("DELETE WHERE { ?job t:INGESTS_TO t:LEGACY_CONTACTS_DUMP }")
115
+ db.save() # or pass autosave=True and skip this
116
+
117
+ db.to_rdflib() # plain rdflib.Graph, if you want to go further
118
+ db.to_html("pipeline.html") # interactive graph workbench (see demos below)
119
+ db.to_jsonld() # best-effort export for real RDF tooling
120
+ ```
121
+
122
+ ## Quickstart (CLI)
123
+
124
+ ```bash
125
+ trikedb add pipeline.yaml salesflow-crm PROVIDES crm-sync-job
126
+ trikedb add pipeline.yaml crm-sync-job INGESTS_TO RAW_CRM_CONTACTS -a schedule=hourly
127
+
128
+ trikedb query pipeline.yaml -w "?vendor PROVIDES ?job" -w "?job INGESTS_TO ?table"
129
+ # vendor job table
130
+ # ------------- ------------ ----------------
131
+ # salesflow-crm crm-sync-job RAW_CRM_CONTACTS
132
+
133
+ trikedb sparql pipeline.yaml \
134
+ "SELECT ?v ?t WHERE { ?v t:PROVIDES ?j . ?j t:INGESTS_TO ?t }"
135
+
136
+ # updates persist straight back to the file
137
+ trikedb sparql pipeline.yaml \
138
+ "INSERT DATA { t:figly t:PROVIDES t:figly-export-job }"
139
+
140
+ trikedb stats pipeline.yaml
141
+ trikedb html pipeline.yaml -o pipeline.html
142
+ trikedb jsonld pipeline.yaml
143
+ ```
144
+
145
+ ## Importing from CSV and Markdown docs
146
+
147
+ The YAML file is the store, but triples can come from wherever your team already writes:
148
+
149
+ ```bash
150
+ # CSV/TSV with an s,p,o header — extra columns become edge attributes
151
+ trikedb import pipeline.yaml new_vendors.csv
152
+
153
+ # Markdown: every table whose header has s/p/o columns is picked up;
154
+ # prose and other tables are ignored. Your design docs are data.
155
+ trikedb import pipeline.yaml design_doc.md
156
+ ```
157
+
158
+ ```markdown
159
+ <!-- anywhere inside an ordinary design doc: -->
160
+ | s | p | o | schedule |
161
+ |-------------------|------------|--------------------|-----------|
162
+ | clickpath-pa | PROVIDES | clickpath-webhook | |
163
+ | clickpath-webhook | INGESTS_TO | RAW_PRODUCT_EVENTS | streaming |
164
+ ```
165
+
166
+ Imports are deterministic — no LLM extraction, so nothing gets invented. The ontology is enforced on the way in, and `"true"`/`"false"` cells become booleans. See [`examples/acme_design_doc.md`](examples/acme_design_doc.md) and [`examples/acme_new_vendors.csv`](examples/acme_new_vendors.csv).
167
+
168
+ ## The file format
169
+
170
+ A trikedb file is ordinary YAML with three top-level keys (only `triples` is required):
171
+
172
+ ```yaml
173
+ ontology: # optional — omit it for free-form predicates
174
+ predicates:
175
+ PROVIDES: "SaaS vendor -> ingestion job"
176
+ AFFECTED_BY: "table -> change event"
177
+
178
+ nodes: # optional — free-form node properties
179
+ salesflow-crm: {type: saas, url: "https://salesflow.example", plan: enterprise}
180
+ RAW_CRM_CONTACTS: {type: table, schema: ACME_RAW, pii: true}
181
+
182
+ triples:
183
+ # compact form for plain facts
184
+ - {s: adastra-ads, p: PROVIDES, o: ads-spend-collector}
185
+
186
+ # any extra keys become edge attributes
187
+ - s: RAW_AD_SPEND_DAILY
188
+ p: AFFECTED_BY
189
+ o: "2025-04-01 adastra API v3: spend now in micros (was cents)"
190
+ ```
191
+
192
+ Three conventions worth stealing (see [`examples/acme_pipeline.yaml`](examples/acme_pipeline.yaml)):
193
+
194
+ - **Change events as objects.** `AFFECTED_BY` edges pointing at dated event strings give your graph a memory — "why did this number change in April?" becomes a query.
195
+ - **`deprecated: true`** on edges renders them dashed in the HTML view and lets agents filter dead paths.
196
+ - **`via:` / `schedule:`** attributes carry operational detail without polluting the node set.
197
+ - **Node properties keep growing.** That's the RDF promise: attach `type`, `url`, `schema`, owners — whatever your team needs — without a schema migration. `type` drives color grouping in the HTML view, and node properties are queryable in SPARQL (`?x t:type "table"`). Set them from code with `db.set_node("RAW_CRM_CONTACTS", pii=True)`.
198
+
199
+ ## An ontology layer for AI agents (MCP)
200
+
201
+ Like the database it takes its analogy from, trikedb is embedded, not hosted. For agents, "embedded" means MCP over stdio — the graph runs inside the agent session, no server to operate:
202
+
203
+ ```bash
204
+ claude mcp add kg -- uvx --from 'trikedb[mcp]' trikedb mcp /absolute/path/to/graph.yaml
205
+ ```
206
+
207
+ The agent gets `sparql`, `match`, `get_node`, `ontology`, `stats` to read, and `add_triple`, `set_node`, `remove_triples`, `import_source` to write. Every write autosaves to the YAML — so agent contributions arrive as reviewable git diffs.
208
+
209
+ This is also the answer to "just throw docs at it": **the agent is the extractor, trikedb is the validated write path.** Point your agent at a pile of documents and ask it to record the facts; it reads them (any format — it's an LLM), calls `add_triple` for each fact, and the ontology rejects any predicate it tries to invent. Extraction stays flexible, the graph stays clean, and a human reviews the diff.
210
+
211
+ ## Using it with LLM agents (no MCP)
212
+
213
+ The zero-setup loop:
214
+
215
+ 1. Keep `graph.yaml` in your repo, next to the code it describes.
216
+ 2. Tell your agent about it once (e.g. in `CLAUDE.md` / your system prompt):
217
+
218
+ > Before any task touching the data pipeline, read `pipeline.yaml`.
219
+ > It is the source of truth for which jobs feed which tables.
220
+ > Predicates are limited to the ontology declared in the file.
221
+
222
+ 3. Agents propose edits as diffs to the YAML — reviewable in a PR like any other change. The ontology check (`trikedb.add` raises on unknown predicates) keeps generated edits inside the vocabulary you chose.
223
+ 4. Humans browse the same graph via `trikedb html`.
224
+
225
+ One source of truth, two projections: YAML for machines, HTML for people.
226
+
227
+ ## What trikedb is not
228
+
229
+ - **Not a SPARQL implementation of its own.** The SPARQL surface is deliberately *not* hand-rolled — your YAML is loaded into [rdflib](https://github.com/RDFLib/rdflib) and queried/updated by rdflib's battle-tested engine. Mapping rule: subjects/predicates become URIs under `urn:trikedb:`; objects with whitespace (change events, notes) become literals. Triples inserted via SPARQL start without edge attributes; surviving triples keep theirs. The lighter `query()`/`triples()` API also exists for quick pattern matching.
230
+ - **Not an extraction pipeline.** It won't turn your PDFs into a graph. Pair it with an extractor if you want that — then curate what comes out.
231
+ - **Not for millions of triples.** Everything is in memory and scans are linear. The sweet spot is the hundreds-to-thousands range, where a curated graph is even possible.
232
+
233
+ ## Examples
234
+
235
+ - [`examples/acme_pipeline.yaml`](examples/acme_pipeline.yaml) — a fictional company's data platform: vendors, ingestion jobs, warehouse tables, change events, migrations. The use case trikedb was born from.
236
+ - [`examples/python_ecosystem.yaml`](examples/python_ecosystem.yaml) — dependencies and deprecations in the Python packaging world, with free-form predicates.
237
+
238
+ ```bash
239
+ trikedb html examples/acme_pipeline.yaml -o acme.html && open acme.html
240
+ ```
241
+
242
+ **Live demos (GitHub Pages):**
243
+
244
+ - [acme knowledge graph](https://ryutoyoda.github.io/trikedb/) — the fictional data platform
245
+ - [python ecosystem](https://ryutoyoda.github.io/trikedb/python_ecosystem.html) — dependencies and deprecations
246
+
247
+ The exported HTML is a small workbench, not just a picture: click a node for a right-hand panel with all its properties (URLs become links), search nodes top-right, and open the **SPARQL console** to run real SPARQL 1.1 in the browser — powered by [Oxigraph](https://github.com/oxigraph/oxigraph) compiled to WASM, loaded from CDN on first use. Change events render as red diamonds with a timeline bar at the bottom.
248
+
249
+ ## Development
250
+
251
+ Uses [uv](https://docs.astral.sh/uv/):
252
+
253
+ ```bash
254
+ uv sync --extra dev
255
+ uv run pytest
256
+ ```
257
+
258
+ ## License
259
+
260
+ MIT
@@ -0,0 +1,234 @@
1
+ <p align="center">
2
+ <img src="docs/logo.svg" width="220" alt="trikedb — a triceratops whose three horns are the triple: subject, predicate, object">
3
+ </p>
4
+
5
+ # trikedb
6
+
7
+ **The DuckDB of graph databases.** You query it like a real triple store — full SPARQL 1.1, reads *and* writes. Underneath, it's a single YAML file. Built for LLM agents.
8
+
9
+ ```yaml
10
+ triples:
11
+ - {s: salesflow-crm, p: PROVIDES, o: crm-sync-job}
12
+ - {s: crm-sync-job, p: INGESTS_TO, o: RAW_CRM_CONTACTS, schedule: hourly}
13
+ - {s: LEGACY_DUMP, p: MIGRATED_TO, o: RAW_CRM_CONTACTS, deprecated: true}
14
+ ```
15
+
16
+ That file **is** the database. No server, no daemon, no cloud deployment. It diffs cleanly in git, survives in a repo next to your code, and — the part trikedb is actually designed around — **an LLM agent can `Read` it directly and reason over your domain without hallucinating entity names.**
17
+
18
+ ## Why
19
+
20
+ RDF graph databases are like Oracle: powerful, correct, and heavy. SPARQL endpoints, OWL reasoners, enterprise semantic layers — great at scale, overkill when what you need is a curated map of a few hundred facts that your AI agents (and teammates) can trust.
21
+
22
+ DuckDB proved the pattern: keep the *interface* of the big system (full SQL, in DuckDB's case) and shrink the *machinery* down to an embedded library over a file. trikedb applies the same move to RDF graph databases — the interface is real SPARQL 1.1 (rdflib's engine, not a homegrown subset), the storage is YAML you can read, diff, and commit:
23
+
24
+ | | A full triple-store deployment | trikedb |
25
+ |---|---|---|
26
+ | Storage | server / cloud service | one YAML file |
27
+ | Query | SPARQL 1.1 | SPARQL 1.1 (same language, rdflib engine) |
28
+ | Writes | SPARQL Update | SPARQL Update — persisted back to the YAML |
29
+ | Schema | OWL + reasoners | a list of allowed predicates |
30
+ | Agent integration | a service to operate | the agent reads the file, or `trikedb mcp` (stdio, embedded) |
31
+ | Setup time | an afternoon (or a sprint) | `pip install trikedb` |
32
+
33
+ If you need inference engines, named graphs, and multi-tenant governance, you want a full enterprise semantic platform. If you want a knowledge graph **today, in a file, in git** — that's trikedb. And because the storage maps cleanly onto RDF, graduating to a bigger system later is an export, not a rewrite: each team keeps its own YAML graph, and stitching them together (or migrating them wholesale) is just merging triples.
34
+
35
+ ### Curation-first, not extraction-first
36
+
37
+ Most "AI knowledge graph" tools use an LLM to extract triples from text. That's great for bootstrapping, but extracted graphs inherit hallucinations. trikedb takes the opposite stance: **the graph is curated data** (by humans, or by agents you supervise), the ontology constrains what can be said, and LLMs *consume* the graph rather than invent it. When an agent reads
38
+
39
+ ```yaml
40
+ - {s: crm-sync-job, p: INGESTS_TO, o: RAW_CRM_CONTACTS}
41
+ ```
42
+
43
+ there is no step where a table name can be made up.
44
+
45
+ ## Install
46
+
47
+ ```bash
48
+ pip install trikedb # library + CLI
49
+ pip install 'trikedb[mcp]' # + MCP server for AI agents
50
+ ```
51
+
52
+ ## Quickstart (Python)
53
+
54
+ ```python
55
+ from trikedb import TrikeDB
56
+
57
+ db = TrikeDB("pipeline.yaml", ontology={
58
+ "PROVIDES": "SaaS vendor -> ingestion job",
59
+ "INGESTS_TO": "ingestion job -> warehouse table",
60
+ "MIGRATED_TO": "deprecated table -> its replacement",
61
+ })
62
+
63
+ db.add("salesflow-crm", "PROVIDES", "crm-sync-job")
64
+ db.add("crm-sync-job", "INGESTS_TO", "RAW_CRM_CONTACTS", schedule="hourly")
65
+ db.add("crm-sync-job", "OWNS", "x") # OntologyError: predicate not declared
66
+
67
+ # Pattern matching — None is a wildcard, '*' globs
68
+ for t in db.triples(p="INGESTS_TO", o="RAW_*"):
69
+ print(t.s, "->", t.o, t.attrs)
70
+
71
+ # Multi-pattern queries with variable joins (zero dependencies)
72
+ db.query(["?vendor PROVIDES ?job", "?job INGESTS_TO ?table"])
73
+ # [{'vendor': 'salesflow-crm', 'job': 'crm-sync-job', 'table': 'RAW_CRM_CONTACTS'}]
74
+
75
+ # Or real SPARQL 1.1 — FILTER, OPTIONAL, aggregates, the lot.
76
+ # Delegated to rdflib, not hand-rolled. The prefix t: is pre-bound.
77
+ db.sparql("""
78
+ SELECT ?vendor ?table WHERE {
79
+ ?vendor t:PROVIDES ?job .
80
+ ?job t:INGESTS_TO ?table .
81
+ FILTER(STRSTARTS(STR(?table), "urn:trikedb:RAW_"))
82
+ }
83
+ """)
84
+ db.sparql("ASK { ?x t:MIGRATED_TO ?y }") # True
85
+
86
+ # Writes go through SPARQL too, DuckDB-style — and land back in the YAML
87
+ db.sparql("INSERT DATA { t:figly t:PROVIDES t:figly-export-job }")
88
+ db.sparql("DELETE WHERE { ?job t:INGESTS_TO t:LEGACY_CONTACTS_DUMP }")
89
+ db.save() # or pass autosave=True and skip this
90
+
91
+ db.to_rdflib() # plain rdflib.Graph, if you want to go further
92
+ db.to_html("pipeline.html") # interactive graph workbench (see demos below)
93
+ db.to_jsonld() # best-effort export for real RDF tooling
94
+ ```
95
+
96
+ ## Quickstart (CLI)
97
+
98
+ ```bash
99
+ trikedb add pipeline.yaml salesflow-crm PROVIDES crm-sync-job
100
+ trikedb add pipeline.yaml crm-sync-job INGESTS_TO RAW_CRM_CONTACTS -a schedule=hourly
101
+
102
+ trikedb query pipeline.yaml -w "?vendor PROVIDES ?job" -w "?job INGESTS_TO ?table"
103
+ # vendor job table
104
+ # ------------- ------------ ----------------
105
+ # salesflow-crm crm-sync-job RAW_CRM_CONTACTS
106
+
107
+ trikedb sparql pipeline.yaml \
108
+ "SELECT ?v ?t WHERE { ?v t:PROVIDES ?j . ?j t:INGESTS_TO ?t }"
109
+
110
+ # updates persist straight back to the file
111
+ trikedb sparql pipeline.yaml \
112
+ "INSERT DATA { t:figly t:PROVIDES t:figly-export-job }"
113
+
114
+ trikedb stats pipeline.yaml
115
+ trikedb html pipeline.yaml -o pipeline.html
116
+ trikedb jsonld pipeline.yaml
117
+ ```
118
+
119
+ ## Importing from CSV and Markdown docs
120
+
121
+ The YAML file is the store, but triples can come from wherever your team already writes:
122
+
123
+ ```bash
124
+ # CSV/TSV with an s,p,o header — extra columns become edge attributes
125
+ trikedb import pipeline.yaml new_vendors.csv
126
+
127
+ # Markdown: every table whose header has s/p/o columns is picked up;
128
+ # prose and other tables are ignored. Your design docs are data.
129
+ trikedb import pipeline.yaml design_doc.md
130
+ ```
131
+
132
+ ```markdown
133
+ <!-- anywhere inside an ordinary design doc: -->
134
+ | s | p | o | schedule |
135
+ |-------------------|------------|--------------------|-----------|
136
+ | clickpath-pa | PROVIDES | clickpath-webhook | |
137
+ | clickpath-webhook | INGESTS_TO | RAW_PRODUCT_EVENTS | streaming |
138
+ ```
139
+
140
+ Imports are deterministic — no LLM extraction, so nothing gets invented. The ontology is enforced on the way in, and `"true"`/`"false"` cells become booleans. See [`examples/acme_design_doc.md`](examples/acme_design_doc.md) and [`examples/acme_new_vendors.csv`](examples/acme_new_vendors.csv).
141
+
142
+ ## The file format
143
+
144
+ A trikedb file is ordinary YAML with three top-level keys (only `triples` is required):
145
+
146
+ ```yaml
147
+ ontology: # optional — omit it for free-form predicates
148
+ predicates:
149
+ PROVIDES: "SaaS vendor -> ingestion job"
150
+ AFFECTED_BY: "table -> change event"
151
+
152
+ nodes: # optional — free-form node properties
153
+ salesflow-crm: {type: saas, url: "https://salesflow.example", plan: enterprise}
154
+ RAW_CRM_CONTACTS: {type: table, schema: ACME_RAW, pii: true}
155
+
156
+ triples:
157
+ # compact form for plain facts
158
+ - {s: adastra-ads, p: PROVIDES, o: ads-spend-collector}
159
+
160
+ # any extra keys become edge attributes
161
+ - s: RAW_AD_SPEND_DAILY
162
+ p: AFFECTED_BY
163
+ o: "2025-04-01 adastra API v3: spend now in micros (was cents)"
164
+ ```
165
+
166
+ Three conventions worth stealing (see [`examples/acme_pipeline.yaml`](examples/acme_pipeline.yaml)):
167
+
168
+ - **Change events as objects.** `AFFECTED_BY` edges pointing at dated event strings give your graph a memory — "why did this number change in April?" becomes a query.
169
+ - **`deprecated: true`** on edges renders them dashed in the HTML view and lets agents filter dead paths.
170
+ - **`via:` / `schedule:`** attributes carry operational detail without polluting the node set.
171
+ - **Node properties keep growing.** That's the RDF promise: attach `type`, `url`, `schema`, owners — whatever your team needs — without a schema migration. `type` drives color grouping in the HTML view, and node properties are queryable in SPARQL (`?x t:type "table"`). Set them from code with `db.set_node("RAW_CRM_CONTACTS", pii=True)`.
172
+
173
+ ## An ontology layer for AI agents (MCP)
174
+
175
+ Like the database it takes its analogy from, trikedb is embedded, not hosted. For agents, "embedded" means MCP over stdio — the graph runs inside the agent session, no server to operate:
176
+
177
+ ```bash
178
+ claude mcp add kg -- uvx --from 'trikedb[mcp]' trikedb mcp /absolute/path/to/graph.yaml
179
+ ```
180
+
181
+ The agent gets `sparql`, `match`, `get_node`, `ontology`, `stats` to read, and `add_triple`, `set_node`, `remove_triples`, `import_source` to write. Every write autosaves to the YAML — so agent contributions arrive as reviewable git diffs.
182
+
183
+ This is also the answer to "just throw docs at it": **the agent is the extractor, trikedb is the validated write path.** Point your agent at a pile of documents and ask it to record the facts; it reads them (any format — it's an LLM), calls `add_triple` for each fact, and the ontology rejects any predicate it tries to invent. Extraction stays flexible, the graph stays clean, and a human reviews the diff.
184
+
185
+ ## Using it with LLM agents (no MCP)
186
+
187
+ The zero-setup loop:
188
+
189
+ 1. Keep `graph.yaml` in your repo, next to the code it describes.
190
+ 2. Tell your agent about it once (e.g. in `CLAUDE.md` / your system prompt):
191
+
192
+ > Before any task touching the data pipeline, read `pipeline.yaml`.
193
+ > It is the source of truth for which jobs feed which tables.
194
+ > Predicates are limited to the ontology declared in the file.
195
+
196
+ 3. Agents propose edits as diffs to the YAML — reviewable in a PR like any other change. The ontology check (`trikedb.add` raises on unknown predicates) keeps generated edits inside the vocabulary you chose.
197
+ 4. Humans browse the same graph via `trikedb html`.
198
+
199
+ One source of truth, two projections: YAML for machines, HTML for people.
200
+
201
+ ## What trikedb is not
202
+
203
+ - **Not a SPARQL implementation of its own.** The SPARQL surface is deliberately *not* hand-rolled — your YAML is loaded into [rdflib](https://github.com/RDFLib/rdflib) and queried/updated by rdflib's battle-tested engine. Mapping rule: subjects/predicates become URIs under `urn:trikedb:`; objects with whitespace (change events, notes) become literals. Triples inserted via SPARQL start without edge attributes; surviving triples keep theirs. The lighter `query()`/`triples()` API also exists for quick pattern matching.
204
+ - **Not an extraction pipeline.** It won't turn your PDFs into a graph. Pair it with an extractor if you want that — then curate what comes out.
205
+ - **Not for millions of triples.** Everything is in memory and scans are linear. The sweet spot is the hundreds-to-thousands range, where a curated graph is even possible.
206
+
207
+ ## Examples
208
+
209
+ - [`examples/acme_pipeline.yaml`](examples/acme_pipeline.yaml) — a fictional company's data platform: vendors, ingestion jobs, warehouse tables, change events, migrations. The use case trikedb was born from.
210
+ - [`examples/python_ecosystem.yaml`](examples/python_ecosystem.yaml) — dependencies and deprecations in the Python packaging world, with free-form predicates.
211
+
212
+ ```bash
213
+ trikedb html examples/acme_pipeline.yaml -o acme.html && open acme.html
214
+ ```
215
+
216
+ **Live demos (GitHub Pages):**
217
+
218
+ - [acme knowledge graph](https://ryutoyoda.github.io/trikedb/) — the fictional data platform
219
+ - [python ecosystem](https://ryutoyoda.github.io/trikedb/python_ecosystem.html) — dependencies and deprecations
220
+
221
+ The exported HTML is a small workbench, not just a picture: click a node for a right-hand panel with all its properties (URLs become links), search nodes top-right, and open the **SPARQL console** to run real SPARQL 1.1 in the browser — powered by [Oxigraph](https://github.com/oxigraph/oxigraph) compiled to WASM, loaded from CDN on first use. Change events render as red diamonds with a timeline bar at the bottom.
222
+
223
+ ## Development
224
+
225
+ Uses [uv](https://docs.astral.sh/uv/):
226
+
227
+ ```bash
228
+ uv sync --extra dev
229
+ uv run pytest
230
+ ```
231
+
232
+ ## License
233
+
234
+ MIT
@@ -0,0 +1,35 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "trikedb"
7
+ version = "0.8.0"
8
+ description = "The DuckDB of graph databases: a knowledge graph that lives in a single YAML file, queried with full SPARQL 1.1. Built for LLM agents."
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ authors = [{ name = "Ryuto Yoda" }]
12
+ requires-python = ">=3.10"
13
+ dependencies = ["PyYAML>=6.0", "rdflib>=7"]
14
+ keywords = ["knowledge-graph", "rdf", "triple-store", "yaml", "llm", "agents", "ontology"]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Topic :: Database",
21
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
22
+ ]
23
+
24
+ [project.urls]
25
+ Homepage = "https://github.com/RyutoYoda/trikedb"
26
+
27
+ [project.optional-dependencies]
28
+ mcp = ["mcp>=1.2,<2"]
29
+ dev = ["pytest>=7", "mcp>=1.2,<2"]
30
+
31
+ [project.scripts]
32
+ trikedb = "trikedb.cli:main"
33
+
34
+ [tool.setuptools.packages.find]
35
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,10 @@
1
+ """trikedb — the DuckDB of graph databases.
2
+
3
+ A knowledge graph that lives in a single YAML file, queried and
4
+ updated with full SPARQL 1.1. Built for LLM agents.
5
+ """
6
+
7
+ from .db import OntologyError, Triple, TrikeDB
8
+
9
+ __version__ = "0.8.0"
10
+ __all__ = ["TrikeDB", "Triple", "OntologyError", "__version__"]