kaygee 0.1.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.
- kaygee-0.1.0/.claude/settings.local.json +22 -0
- kaygee-0.1.0/.github/workflows/tests.yml +27 -0
- kaygee-0.1.0/.gitignore +9 -0
- kaygee-0.1.0/Makefile +19 -0
- kaygee-0.1.0/PKG-INFO +176 -0
- kaygee-0.1.0/README.md +155 -0
- kaygee-0.1.0/examples/biology.html +966 -0
- kaygee-0.1.0/examples/cognitive_science.html +966 -0
- kaygee-0.1.0/examples/music_theory.html +966 -0
- kaygee-0.1.0/examples/software_architecture.html +966 -0
- kaygee-0.1.0/generate_examples.py +564 -0
- kaygee-0.1.0/notebooks/knowledge_graph_demo.ipynb +637 -0
- kaygee-0.1.0/pyproject.toml +49 -0
- kaygee-0.1.0/src/kaygee/__init__.py +53 -0
- kaygee-0.1.0/src/kaygee/constraints.py +232 -0
- kaygee-0.1.0/src/kaygee/core.py +1036 -0
- kaygee-0.1.0/src/kaygee/shell.py +580 -0
- kaygee-0.1.0/src/kaygee/sync.py +378 -0
- kaygee-0.1.0/src/kaygee/viz.py +1078 -0
- kaygee-0.1.0/tests/__init__.py +0 -0
- kaygee-0.1.0/tests/conftest.py +47 -0
- kaygee-0.1.0/tests/test_changelog.py +174 -0
- kaygee-0.1.0/tests/test_chaos.py +1255 -0
- kaygee-0.1.0/tests/test_constraints.py +357 -0
- kaygee-0.1.0/tests/test_edge_cases.py +169 -0
- kaygee-0.1.0/tests/test_frontmatter_integration.py +130 -0
- kaygee-0.1.0/tests/test_graph_shell.py +36 -0
- kaygee-0.1.0/tests/test_info_query.py +105 -0
- kaygee-0.1.0/tests/test_nodes.py +342 -0
- kaygee-0.1.0/tests/test_parsing.py +186 -0
- kaygee-0.1.0/tests/test_persistence.py +79 -0
- kaygee-0.1.0/tests/test_read.py +94 -0
- kaygee-0.1.0/tests/test_shell_commands.py +341 -0
- kaygee-0.1.0/tests/test_stress.py +634 -0
- kaygee-0.1.0/tests/test_sync.py +480 -0
- kaygee-0.1.0/tests/test_visualization.py +173 -0
- kaygee-0.1.0/tests/test_wikilinks.py +204 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"WebSearch",
|
|
5
|
+
"Bash(python3:*)",
|
|
6
|
+
"Bash(wc:*)",
|
|
7
|
+
"WebFetch(domain:github.com)",
|
|
8
|
+
"WebFetch(domain:docs.turso.tech)",
|
|
9
|
+
"WebFetch(domain:pypi.org)",
|
|
10
|
+
"WebFetch(domain:www.powersync.com)",
|
|
11
|
+
"WebFetch(domain:techouse.github.io)",
|
|
12
|
+
"WebFetch(domain:philipotoole.com)",
|
|
13
|
+
"Bash(python -m pytest tests/test_changelog.py tests/test_sync.py -v -p no:deepeval)",
|
|
14
|
+
"Bash(uv run pytest:*)",
|
|
15
|
+
"Bash(python -m pytest:*)",
|
|
16
|
+
"Bash(grep:*)",
|
|
17
|
+
"Bash(/Users/tanmaygupta/dev/kaybee/tests/conftest.py:*)",
|
|
18
|
+
"Bash(python -c:*)",
|
|
19
|
+
"Bash(curl:*)"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
strategy:
|
|
11
|
+
matrix:
|
|
12
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout
|
|
15
|
+
uses: actions/checkout@v4
|
|
16
|
+
- name: Set up Python
|
|
17
|
+
uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: ${{ matrix.python-version }}
|
|
20
|
+
- name: Set up uv
|
|
21
|
+
uses: astral-sh/setup-uv@v4
|
|
22
|
+
with:
|
|
23
|
+
version: "0.4.20"
|
|
24
|
+
- name: Install deps
|
|
25
|
+
run: uv sync --dev
|
|
26
|
+
- name: Run tests
|
|
27
|
+
run: make test
|
kaygee-0.1.0/.gitignore
ADDED
kaygee-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
.PHONY: install test test-verbose publish clean
|
|
2
|
+
|
|
3
|
+
install:
|
|
4
|
+
uv sync --dev
|
|
5
|
+
|
|
6
|
+
test:
|
|
7
|
+
uv run pytest
|
|
8
|
+
|
|
9
|
+
test-verbose:
|
|
10
|
+
uv run pytest -vv
|
|
11
|
+
|
|
12
|
+
publish:
|
|
13
|
+
rm -rf dist
|
|
14
|
+
uv build
|
|
15
|
+
uv run twine upload --repository pypi dist/kaygee-*
|
|
16
|
+
|
|
17
|
+
clean:
|
|
18
|
+
rm -rf dist
|
|
19
|
+
find . -name "__pycache__" -type d -prune -exec rm -rf {} +
|
kaygee-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kaygee
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A flat, SQLite-native knowledge graph with YAML frontmatter and wikilinks
|
|
5
|
+
Project-URL: Homepage, https://github.com/tg1482/kaygee
|
|
6
|
+
Project-URL: Repository, https://github.com/tg1482/kaygee
|
|
7
|
+
Author-email: Tanmay Gupta <tg1482@stern.nyu.edu>
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: agents,frontmatter,knowledge-graph,llm,sqlite,wikilinks
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# kaygee
|
|
23
|
+
|
|
24
|
+
Flat, SQLite-native knowledge graph for agent memory.
|
|
25
|
+
|
|
26
|
+
## What it is
|
|
27
|
+
|
|
28
|
+
A knowledge graph stored in SQLite. Nodes have YAML frontmatter, link to each other with `[[wikilinks]]`, and self-organize into typed tables. No schema upfront — it emerges from the data you write.
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from kaygee import KnowledgeGraph
|
|
32
|
+
|
|
33
|
+
kg = KnowledgeGraph("brain.db")
|
|
34
|
+
|
|
35
|
+
kg.write("spreading-activation", """---
|
|
36
|
+
type: concept
|
|
37
|
+
description: How activation propagates through a network
|
|
38
|
+
tags: [cognition, search]
|
|
39
|
+
---
|
|
40
|
+
Follows [[agent-traversal]] paths and uses [[semantic-similarity]].""")
|
|
41
|
+
|
|
42
|
+
kg.write("turing", """---
|
|
43
|
+
type: person
|
|
44
|
+
role: researcher
|
|
45
|
+
born: 1912
|
|
46
|
+
---
|
|
47
|
+
Pioneered computation and [[agent-traversal]].""")
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
That's it. Types are tracked, links are resolved, backlinks work automatically.
|
|
51
|
+
|
|
52
|
+
Internally, all node data lives in a single `_data` table. A `_type_fields` table tracks which columns belong to which type. The `nodes` table is a thin index of name + type.
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
# Raw SQL is available when you need it
|
|
56
|
+
kg.query("SELECT name, description FROM _data WHERE name = ?", ("spreading-activation",))
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Core operations
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
# Write and read
|
|
63
|
+
kg.write("name", "---\ntype: concept\n---\nBody text with [[links]].")
|
|
64
|
+
kg.cat("name") # full content (frontmatter + body)
|
|
65
|
+
kg.body("name") # body only
|
|
66
|
+
kg.frontmatter("name") # metadata dict
|
|
67
|
+
kg.read("name", depth=1) # this node + content of linked nodes
|
|
68
|
+
|
|
69
|
+
# Organize
|
|
70
|
+
kg.touch("name") # create if not exists
|
|
71
|
+
kg.rm("name") # delete
|
|
72
|
+
kg.mv("old", "new") # rename
|
|
73
|
+
kg.cp("src", "dst") # copy
|
|
74
|
+
|
|
75
|
+
# Search
|
|
76
|
+
kg.ls("concept") # nodes of type
|
|
77
|
+
kg.find(name="activ.*") # regex on names
|
|
78
|
+
kg.grep("pattern", content=True) # regex across content
|
|
79
|
+
kg.tags() # {tag: [node, ...]} mapping
|
|
80
|
+
|
|
81
|
+
# Graph
|
|
82
|
+
kg.wikilinks("name") # outgoing link targets
|
|
83
|
+
kg.backlinks("name") # who links here
|
|
84
|
+
kg.graph() # full adjacency dict
|
|
85
|
+
kg.schema() # {type: [fields]} across all types
|
|
86
|
+
|
|
87
|
+
# Raw SQL
|
|
88
|
+
kg.query("SELECT name FROM nodes WHERE type = ?", ("concept",))
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Changelog
|
|
92
|
+
|
|
93
|
+
Every mutation is recorded in an append-only changelog (enabled by default). This drives delta sync and audit trails.
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
kg = KnowledgeGraph("brain.db") # changelog=True by default
|
|
97
|
+
|
|
98
|
+
kg.write("sa", "---\ntype: concept\n---\nSpreading activation.")
|
|
99
|
+
kg.rm("sa")
|
|
100
|
+
|
|
101
|
+
entries = kg.changelog(since_seq=0, limit=100)
|
|
102
|
+
# [(1, '2026-...', 'node.write', 'sa', '{"type": "concept", ...}'),
|
|
103
|
+
# (2, '2026-...', 'node.rm', 'sa', '{"type": "concept"}')]
|
|
104
|
+
|
|
105
|
+
kg.changelog_truncate(before_seq=2) # prune old entries
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Operations logged: `node.write`, `node.rm`, `node.mv`, `node.cp`, `node.type_change`, `type.add`, `type.rm`.
|
|
109
|
+
|
|
110
|
+
Disable with `KnowledgeGraph("brain.db", changelog=False)` if you don't need it.
|
|
111
|
+
|
|
112
|
+
## Sync
|
|
113
|
+
|
|
114
|
+
Push local changes to a remote MySQL database, scoped by team/user/project. Pull to replicate back.
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from kaygee import sync_push, sync_pull
|
|
118
|
+
|
|
119
|
+
# Push changelog deltas to MySQL (only changed rows sent)
|
|
120
|
+
last_seq = sync_push(kg, mysql_conn, scope={"team_id": "eng"}, since_seq=0)
|
|
121
|
+
# Persist last_seq for next call
|
|
122
|
+
|
|
123
|
+
# Pull all rows matching scope from MySQL into local SQLite
|
|
124
|
+
count = sync_pull(kg, mysql_conn, scope={"team_id": "eng"})
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
- **Push** replays changelog entries — upserts and deletes flow through, including type changes and renames.
|
|
128
|
+
- **Pull** is a full pull filtered by scope. Writes bypass the changelog to avoid push-back loops.
|
|
129
|
+
- Falls back to full-table-scan push when changelog is disabled (deletes not propagated in this mode).
|
|
130
|
+
|
|
131
|
+
## Constraints
|
|
132
|
+
|
|
133
|
+
Free-form by default. Add structure when you want it.
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from kaygee import Validator, freeze_schema, requires_field, requires_link, no_orphans
|
|
137
|
+
|
|
138
|
+
v = Validator()
|
|
139
|
+
v.add(freeze_schema("concept", ["description", "tags"]))
|
|
140
|
+
v.add(requires_field("concept", "description"))
|
|
141
|
+
v.add(requires_link("paper", target_type="person"))
|
|
142
|
+
v.add(no_orphans())
|
|
143
|
+
|
|
144
|
+
v.check(kg) # raises ValidationError with all violations
|
|
145
|
+
kg.set_validator(v) # gatekeeper: blocks invalid writes before they persist
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Shell
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
from kaygee import GraphShell
|
|
152
|
+
|
|
153
|
+
sh = GraphShell(kg)
|
|
154
|
+
sh.run("touch", ["neuron", "---\ntype: concept\n---\nA unit of [[computation]]."])
|
|
155
|
+
sh.run("ls", ["concept"])
|
|
156
|
+
sh.run("links", ["neuron"])
|
|
157
|
+
sh.execute("cat neuron | grep computation")
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Visualization
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
from kaygee import visualize
|
|
164
|
+
|
|
165
|
+
visualize(kg, path="graph.html") # self-contained interactive HTML
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Install
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
pip install kaygee
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## License
|
|
175
|
+
|
|
176
|
+
MIT
|
kaygee-0.1.0/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# kaygee
|
|
2
|
+
|
|
3
|
+
Flat, SQLite-native knowledge graph for agent memory.
|
|
4
|
+
|
|
5
|
+
## What it is
|
|
6
|
+
|
|
7
|
+
A knowledge graph stored in SQLite. Nodes have YAML frontmatter, link to each other with `[[wikilinks]]`, and self-organize into typed tables. No schema upfront — it emerges from the data you write.
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from kaygee import KnowledgeGraph
|
|
11
|
+
|
|
12
|
+
kg = KnowledgeGraph("brain.db")
|
|
13
|
+
|
|
14
|
+
kg.write("spreading-activation", """---
|
|
15
|
+
type: concept
|
|
16
|
+
description: How activation propagates through a network
|
|
17
|
+
tags: [cognition, search]
|
|
18
|
+
---
|
|
19
|
+
Follows [[agent-traversal]] paths and uses [[semantic-similarity]].""")
|
|
20
|
+
|
|
21
|
+
kg.write("turing", """---
|
|
22
|
+
type: person
|
|
23
|
+
role: researcher
|
|
24
|
+
born: 1912
|
|
25
|
+
---
|
|
26
|
+
Pioneered computation and [[agent-traversal]].""")
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
That's it. Types are tracked, links are resolved, backlinks work automatically.
|
|
30
|
+
|
|
31
|
+
Internally, all node data lives in a single `_data` table. A `_type_fields` table tracks which columns belong to which type. The `nodes` table is a thin index of name + type.
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
# Raw SQL is available when you need it
|
|
35
|
+
kg.query("SELECT name, description FROM _data WHERE name = ?", ("spreading-activation",))
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Core operations
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
# Write and read
|
|
42
|
+
kg.write("name", "---\ntype: concept\n---\nBody text with [[links]].")
|
|
43
|
+
kg.cat("name") # full content (frontmatter + body)
|
|
44
|
+
kg.body("name") # body only
|
|
45
|
+
kg.frontmatter("name") # metadata dict
|
|
46
|
+
kg.read("name", depth=1) # this node + content of linked nodes
|
|
47
|
+
|
|
48
|
+
# Organize
|
|
49
|
+
kg.touch("name") # create if not exists
|
|
50
|
+
kg.rm("name") # delete
|
|
51
|
+
kg.mv("old", "new") # rename
|
|
52
|
+
kg.cp("src", "dst") # copy
|
|
53
|
+
|
|
54
|
+
# Search
|
|
55
|
+
kg.ls("concept") # nodes of type
|
|
56
|
+
kg.find(name="activ.*") # regex on names
|
|
57
|
+
kg.grep("pattern", content=True) # regex across content
|
|
58
|
+
kg.tags() # {tag: [node, ...]} mapping
|
|
59
|
+
|
|
60
|
+
# Graph
|
|
61
|
+
kg.wikilinks("name") # outgoing link targets
|
|
62
|
+
kg.backlinks("name") # who links here
|
|
63
|
+
kg.graph() # full adjacency dict
|
|
64
|
+
kg.schema() # {type: [fields]} across all types
|
|
65
|
+
|
|
66
|
+
# Raw SQL
|
|
67
|
+
kg.query("SELECT name FROM nodes WHERE type = ?", ("concept",))
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Changelog
|
|
71
|
+
|
|
72
|
+
Every mutation is recorded in an append-only changelog (enabled by default). This drives delta sync and audit trails.
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
kg = KnowledgeGraph("brain.db") # changelog=True by default
|
|
76
|
+
|
|
77
|
+
kg.write("sa", "---\ntype: concept\n---\nSpreading activation.")
|
|
78
|
+
kg.rm("sa")
|
|
79
|
+
|
|
80
|
+
entries = kg.changelog(since_seq=0, limit=100)
|
|
81
|
+
# [(1, '2026-...', 'node.write', 'sa', '{"type": "concept", ...}'),
|
|
82
|
+
# (2, '2026-...', 'node.rm', 'sa', '{"type": "concept"}')]
|
|
83
|
+
|
|
84
|
+
kg.changelog_truncate(before_seq=2) # prune old entries
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Operations logged: `node.write`, `node.rm`, `node.mv`, `node.cp`, `node.type_change`, `type.add`, `type.rm`.
|
|
88
|
+
|
|
89
|
+
Disable with `KnowledgeGraph("brain.db", changelog=False)` if you don't need it.
|
|
90
|
+
|
|
91
|
+
## Sync
|
|
92
|
+
|
|
93
|
+
Push local changes to a remote MySQL database, scoped by team/user/project. Pull to replicate back.
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from kaygee import sync_push, sync_pull
|
|
97
|
+
|
|
98
|
+
# Push changelog deltas to MySQL (only changed rows sent)
|
|
99
|
+
last_seq = sync_push(kg, mysql_conn, scope={"team_id": "eng"}, since_seq=0)
|
|
100
|
+
# Persist last_seq for next call
|
|
101
|
+
|
|
102
|
+
# Pull all rows matching scope from MySQL into local SQLite
|
|
103
|
+
count = sync_pull(kg, mysql_conn, scope={"team_id": "eng"})
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
- **Push** replays changelog entries — upserts and deletes flow through, including type changes and renames.
|
|
107
|
+
- **Pull** is a full pull filtered by scope. Writes bypass the changelog to avoid push-back loops.
|
|
108
|
+
- Falls back to full-table-scan push when changelog is disabled (deletes not propagated in this mode).
|
|
109
|
+
|
|
110
|
+
## Constraints
|
|
111
|
+
|
|
112
|
+
Free-form by default. Add structure when you want it.
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from kaygee import Validator, freeze_schema, requires_field, requires_link, no_orphans
|
|
116
|
+
|
|
117
|
+
v = Validator()
|
|
118
|
+
v.add(freeze_schema("concept", ["description", "tags"]))
|
|
119
|
+
v.add(requires_field("concept", "description"))
|
|
120
|
+
v.add(requires_link("paper", target_type="person"))
|
|
121
|
+
v.add(no_orphans())
|
|
122
|
+
|
|
123
|
+
v.check(kg) # raises ValidationError with all violations
|
|
124
|
+
kg.set_validator(v) # gatekeeper: blocks invalid writes before they persist
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Shell
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
from kaygee import GraphShell
|
|
131
|
+
|
|
132
|
+
sh = GraphShell(kg)
|
|
133
|
+
sh.run("touch", ["neuron", "---\ntype: concept\n---\nA unit of [[computation]]."])
|
|
134
|
+
sh.run("ls", ["concept"])
|
|
135
|
+
sh.run("links", ["neuron"])
|
|
136
|
+
sh.execute("cat neuron | grep computation")
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Visualization
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from kaygee import visualize
|
|
143
|
+
|
|
144
|
+
visualize(kg, path="graph.html") # self-contained interactive HTML
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Install
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
pip install kaygee
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
MIT
|