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.
Files changed (37) hide show
  1. kaygee-0.1.0/.claude/settings.local.json +22 -0
  2. kaygee-0.1.0/.github/workflows/tests.yml +27 -0
  3. kaygee-0.1.0/.gitignore +9 -0
  4. kaygee-0.1.0/Makefile +19 -0
  5. kaygee-0.1.0/PKG-INFO +176 -0
  6. kaygee-0.1.0/README.md +155 -0
  7. kaygee-0.1.0/examples/biology.html +966 -0
  8. kaygee-0.1.0/examples/cognitive_science.html +966 -0
  9. kaygee-0.1.0/examples/music_theory.html +966 -0
  10. kaygee-0.1.0/examples/software_architecture.html +966 -0
  11. kaygee-0.1.0/generate_examples.py +564 -0
  12. kaygee-0.1.0/notebooks/knowledge_graph_demo.ipynb +637 -0
  13. kaygee-0.1.0/pyproject.toml +49 -0
  14. kaygee-0.1.0/src/kaygee/__init__.py +53 -0
  15. kaygee-0.1.0/src/kaygee/constraints.py +232 -0
  16. kaygee-0.1.0/src/kaygee/core.py +1036 -0
  17. kaygee-0.1.0/src/kaygee/shell.py +580 -0
  18. kaygee-0.1.0/src/kaygee/sync.py +378 -0
  19. kaygee-0.1.0/src/kaygee/viz.py +1078 -0
  20. kaygee-0.1.0/tests/__init__.py +0 -0
  21. kaygee-0.1.0/tests/conftest.py +47 -0
  22. kaygee-0.1.0/tests/test_changelog.py +174 -0
  23. kaygee-0.1.0/tests/test_chaos.py +1255 -0
  24. kaygee-0.1.0/tests/test_constraints.py +357 -0
  25. kaygee-0.1.0/tests/test_edge_cases.py +169 -0
  26. kaygee-0.1.0/tests/test_frontmatter_integration.py +130 -0
  27. kaygee-0.1.0/tests/test_graph_shell.py +36 -0
  28. kaygee-0.1.0/tests/test_info_query.py +105 -0
  29. kaygee-0.1.0/tests/test_nodes.py +342 -0
  30. kaygee-0.1.0/tests/test_parsing.py +186 -0
  31. kaygee-0.1.0/tests/test_persistence.py +79 -0
  32. kaygee-0.1.0/tests/test_read.py +94 -0
  33. kaygee-0.1.0/tests/test_shell_commands.py +341 -0
  34. kaygee-0.1.0/tests/test_stress.py +634 -0
  35. kaygee-0.1.0/tests/test_sync.py +480 -0
  36. kaygee-0.1.0/tests/test_visualization.py +173 -0
  37. 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
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .pytest_cache/
8
+ .DS_Store
9
+ uv.lock
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