schist 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.
- schist-0.1.0/PKG-INFO +96 -0
- schist-0.1.0/README.md +74 -0
- schist-0.1.0/pyproject.toml +56 -0
- schist-0.1.0/schist/__init__.py +0 -0
- schist-0.1.0/schist/__main__.py +122 -0
- schist-0.1.0/schist/acl.py +352 -0
- schist-0.1.0/schist/commands.py +235 -0
- schist-0.1.0/schist/git_ops.py +161 -0
- schist-0.1.0/schist/ingest.py +265 -0
- schist-0.1.0/schist/markdown_io.py +63 -0
- schist-0.1.0/schist/pre_receive.py +373 -0
- schist-0.1.0/schist/rate_limit.py +300 -0
- schist-0.1.0/schist/schema.sql +103 -0
- schist-0.1.0/schist/seed-domains.sql +24 -0
- schist-0.1.0/schist/spoke_config.py +51 -0
- schist-0.1.0/schist/sqlite_query.py +119 -0
- schist-0.1.0/schist/sync.py +799 -0
- schist-0.1.0/schist.egg-info/PKG-INFO +96 -0
- schist-0.1.0/schist.egg-info/SOURCES.txt +31 -0
- schist-0.1.0/schist.egg-info/dependency_links.txt +1 -0
- schist-0.1.0/schist.egg-info/entry_points.txt +3 -0
- schist-0.1.0/schist.egg-info/requires.txt +2 -0
- schist-0.1.0/schist.egg-info/top_level.txt +1 -0
- schist-0.1.0/setup.cfg +4 -0
- schist-0.1.0/tests/test_acl.py +593 -0
- schist-0.1.0/tests/test_hub.py +174 -0
- schist-0.1.0/tests/test_hub_spoke_e2e.py +122 -0
- schist-0.1.0/tests/test_ingest.py +250 -0
- schist-0.1.0/tests/test_init_standalone.py +420 -0
- schist-0.1.0/tests/test_pre_receive.py +667 -0
- schist-0.1.0/tests/test_rate_limit.py +668 -0
- schist-0.1.0/tests/test_spoke_config.py +36 -0
- schist-0.1.0/tests/test_sync.py +698 -0
schist-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: schist
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Agent-first knowledge graph: git is truth, SQLite is query, humans just watch
|
|
5
|
+
Author: schist contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/yibeichan/schist
|
|
8
|
+
Project-URL: Repository, https://github.com/yibeichan/schist
|
|
9
|
+
Project-URL: Issues, https://github.com/yibeichan/schist/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/yibeichan/schist/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: knowledge-graph,agents,mcp,markdown,sqlite
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
Requires-Dist: python-frontmatter>=1.1.0
|
|
21
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
22
|
+
|
|
23
|
+
# schist
|
|
24
|
+
|
|
25
|
+
Agent-first knowledge graph. Git is truth, SQLite is query, humans just watch.
|
|
26
|
+
|
|
27
|
+
**schist** is a generic, domain-agnostic knowledge graph where AI agents are the primary writers. Content is markdown + YAML frontmatter, version-controlled in git. SQLite provides the query layer. A static web viewer (D3.js + lunr.js) gives humans a read-only visualization.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install schist
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This installs the `schist` CLI and the `schist-ingest` console script (used by the git post-commit hook).
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Create a vault
|
|
41
|
+
mkdir -p ~/vaults/research/{notes,papers,concepts,.schist}
|
|
42
|
+
|
|
43
|
+
# Add your first note
|
|
44
|
+
schist add --vault ~/vaults/research \
|
|
45
|
+
--title "First Note" \
|
|
46
|
+
--tags getting-started \
|
|
47
|
+
--body "Hello, knowledge graph."
|
|
48
|
+
|
|
49
|
+
# Search it
|
|
50
|
+
schist search --vault ~/vaults/research "knowledge"
|
|
51
|
+
|
|
52
|
+
# Get graph context (useful for agent session start)
|
|
53
|
+
schist context --vault ~/vaults/research
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## CLI Commands
|
|
57
|
+
|
|
58
|
+
| Command | Description |
|
|
59
|
+
|---------|-------------|
|
|
60
|
+
| `schist add` | Create a new note |
|
|
61
|
+
| `schist link` | Add a connection between nodes |
|
|
62
|
+
| `schist search` | Full-text search |
|
|
63
|
+
| `schist query` | Raw SQL query |
|
|
64
|
+
| `schist build` | Generate static viewer data |
|
|
65
|
+
| `schist context` | Dump session context |
|
|
66
|
+
| `schist schema` | Print or validate schema |
|
|
67
|
+
|
|
68
|
+
## MCP Server
|
|
69
|
+
|
|
70
|
+
The schist MCP server (`@schist/mcp-server`) is published separately on npm:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm install -g @schist/mcp-server
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Add to `~/.claude/settings.json`:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"mcpServers": {
|
|
81
|
+
"schist": {
|
|
82
|
+
"command": "node",
|
|
83
|
+
"args": ["/absolute/path/to/schist/mcp-server/dist/index.js"],
|
|
84
|
+
"env": {
|
|
85
|
+
"SCHIST_VAULT_PATH": "/absolute/path/to/vault"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
See the [full README](https://github.com/yibeichan/schist#readme) for architecture docs, hub & spoke setup, and MCP tool reference.
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
MIT
|
schist-0.1.0/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# schist
|
|
2
|
+
|
|
3
|
+
Agent-first knowledge graph. Git is truth, SQLite is query, humans just watch.
|
|
4
|
+
|
|
5
|
+
**schist** is a generic, domain-agnostic knowledge graph where AI agents are the primary writers. Content is markdown + YAML frontmatter, version-controlled in git. SQLite provides the query layer. A static web viewer (D3.js + lunr.js) gives humans a read-only visualization.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install schist
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This installs the `schist` CLI and the `schist-ingest` console script (used by the git post-commit hook).
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Create a vault
|
|
19
|
+
mkdir -p ~/vaults/research/{notes,papers,concepts,.schist}
|
|
20
|
+
|
|
21
|
+
# Add your first note
|
|
22
|
+
schist add --vault ~/vaults/research \
|
|
23
|
+
--title "First Note" \
|
|
24
|
+
--tags getting-started \
|
|
25
|
+
--body "Hello, knowledge graph."
|
|
26
|
+
|
|
27
|
+
# Search it
|
|
28
|
+
schist search --vault ~/vaults/research "knowledge"
|
|
29
|
+
|
|
30
|
+
# Get graph context (useful for agent session start)
|
|
31
|
+
schist context --vault ~/vaults/research
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## CLI Commands
|
|
35
|
+
|
|
36
|
+
| Command | Description |
|
|
37
|
+
|---------|-------------|
|
|
38
|
+
| `schist add` | Create a new note |
|
|
39
|
+
| `schist link` | Add a connection between nodes |
|
|
40
|
+
| `schist search` | Full-text search |
|
|
41
|
+
| `schist query` | Raw SQL query |
|
|
42
|
+
| `schist build` | Generate static viewer data |
|
|
43
|
+
| `schist context` | Dump session context |
|
|
44
|
+
| `schist schema` | Print or validate schema |
|
|
45
|
+
|
|
46
|
+
## MCP Server
|
|
47
|
+
|
|
48
|
+
The schist MCP server (`@schist/mcp-server`) is published separately on npm:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install -g @schist/mcp-server
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Add to `~/.claude/settings.json`:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"mcpServers": {
|
|
59
|
+
"schist": {
|
|
60
|
+
"command": "node",
|
|
61
|
+
"args": ["/absolute/path/to/schist/mcp-server/dist/index.js"],
|
|
62
|
+
"env": {
|
|
63
|
+
"SCHIST_VAULT_PATH": "/absolute/path/to/vault"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
See the [full README](https://github.com/yibeichan/schist#readme) for architecture docs, hub & spoke setup, and MCP tool reference.
|
|
71
|
+
|
|
72
|
+
## License
|
|
73
|
+
|
|
74
|
+
MIT
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=82.0.1"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "schist"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Agent-first knowledge graph: git is truth, SQLite is query, humans just watch"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "schist contributors" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["knowledge-graph", "agents", "mcp", "markdown", "sqlite"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
23
|
+
]
|
|
24
|
+
dependencies = ["python-frontmatter>=1.1.0", "pyyaml>=6.0.3"]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/yibeichan/schist"
|
|
28
|
+
Repository = "https://github.com/yibeichan/schist"
|
|
29
|
+
Issues = "https://github.com/yibeichan/schist/issues"
|
|
30
|
+
Changelog = "https://github.com/yibeichan/schist/blob/main/CHANGELOG.md"
|
|
31
|
+
|
|
32
|
+
[project.scripts]
|
|
33
|
+
schist = "schist.__main__:main"
|
|
34
|
+
schist-ingest = "schist.ingest:main"
|
|
35
|
+
|
|
36
|
+
# Explicit package list — without this, setuptools 82+ flat-layout
|
|
37
|
+
# auto-discovery fails when a local `cli/hooks/` directory exists (as
|
|
38
|
+
# created by test_rate_limit.py's `rejected-pushes.log`, which lands
|
|
39
|
+
# under cli/hooks/ by default even though the log file is gitignored).
|
|
40
|
+
# setuptools then errors with "Multiple top-level packages discovered in
|
|
41
|
+
# a flat-layout: ['hooks', 'schist']" because .gitignore is invisible
|
|
42
|
+
# to it. Pinning packages to ["schist"] makes the install deterministic
|
|
43
|
+
# regardless of stray local directories.
|
|
44
|
+
[tool.setuptools]
|
|
45
|
+
packages = ["schist"]
|
|
46
|
+
|
|
47
|
+
# Ship .sql files (schema.sql, seed-domains.sql) inside the wheel so
|
|
48
|
+
# `schist-ingest` works after `pip install schist` — ingest.py reads
|
|
49
|
+
# schema.sql via Path(__file__).parent / 'schema.sql'.
|
|
50
|
+
[tool.setuptools.package-data]
|
|
51
|
+
schist = ["*.sql"]
|
|
52
|
+
|
|
53
|
+
[tool.pytest.ini_options]
|
|
54
|
+
markers = [
|
|
55
|
+
"integration: slow tests that spawn real git subprocesses",
|
|
56
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""schist CLI — agent-first knowledge graph."""
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
from . import commands, sync
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main():
|
|
12
|
+
parser = argparse.ArgumentParser(prog='schist', description='Agent-first knowledge graph CLI')
|
|
13
|
+
parser.add_argument('--vault', default=os.environ.get('SCHIST_VAULT_PATH'), help='Path to vault root (or set SCHIST_VAULT_PATH)')
|
|
14
|
+
parser.add_argument('--db', default=None, help='Path to SQLite database (default: <vault>/.schist/schist.db)')
|
|
15
|
+
|
|
16
|
+
sub = parser.add_subparsers(dest='command')
|
|
17
|
+
|
|
18
|
+
# add
|
|
19
|
+
p_add = sub.add_parser('add', help='Create a new note')
|
|
20
|
+
p_add.add_argument('--title', required=True)
|
|
21
|
+
p_add.add_argument('--body', default=None)
|
|
22
|
+
p_add.add_argument('--tags', default=None, help='Comma-separated tags')
|
|
23
|
+
p_add.add_argument('--concepts', default=None, help='Comma-separated concept slugs')
|
|
24
|
+
p_add.add_argument('--status', default='draft')
|
|
25
|
+
p_add.add_argument('--dir', default='notes', dest='directory')
|
|
26
|
+
|
|
27
|
+
# link
|
|
28
|
+
p_link = sub.add_parser('link', help='Add a connection between documents')
|
|
29
|
+
p_link.add_argument('--source', required=True)
|
|
30
|
+
p_link.add_argument('--target', required=True)
|
|
31
|
+
p_link.add_argument('--type', required=True, dest='link_type')
|
|
32
|
+
p_link.add_argument('--context', default=None)
|
|
33
|
+
|
|
34
|
+
# search
|
|
35
|
+
p_search = sub.add_parser('search', help='Full-text search')
|
|
36
|
+
p_search.add_argument('query', help='Search query')
|
|
37
|
+
p_search.add_argument('--limit', type=int, default=20)
|
|
38
|
+
p_search.add_argument('--status', default=None)
|
|
39
|
+
p_search.add_argument('--tags', default=None, help='Comma-separated AND filter')
|
|
40
|
+
|
|
41
|
+
# query
|
|
42
|
+
p_query = sub.add_parser('query', help='Run a SELECT query')
|
|
43
|
+
p_query.add_argument('sql', help='SQL query (SELECT only)')
|
|
44
|
+
p_query.add_argument('--json', action='store_true', dest='as_json')
|
|
45
|
+
|
|
46
|
+
# build
|
|
47
|
+
p_build = sub.add_parser('build', help='Build graph and search index')
|
|
48
|
+
p_build.add_argument('--out', default=None, help='Output directory (default: <vault>/.schist/data/)')
|
|
49
|
+
|
|
50
|
+
# context
|
|
51
|
+
p_context = sub.add_parser('context', help='Print vault context summary')
|
|
52
|
+
p_context.add_argument('--depth', choices=['minimal', 'standard', 'full'], default='standard')
|
|
53
|
+
|
|
54
|
+
# schema
|
|
55
|
+
p_schema = sub.add_parser('schema', help='Print or validate schema')
|
|
56
|
+
p_schema.add_argument('--validate', action='store_true')
|
|
57
|
+
|
|
58
|
+
# init
|
|
59
|
+
p_init = sub.add_parser('init', help='Initialize a vault (standalone, hub, or spoke)')
|
|
60
|
+
p_init.add_argument('path', nargs='?', default=None,
|
|
61
|
+
help='(standalone) Path to new vault (default: current dir)')
|
|
62
|
+
p_init.add_argument('--spoke', action='store_true', help='Initialize as spoke vault')
|
|
63
|
+
p_init.add_argument('--hub', help='(spoke) Hub repository URL')
|
|
64
|
+
p_init.add_argument('--scope', help='(spoke) Scope to sync (directory path)')
|
|
65
|
+
p_init.add_argument('--identity', default=os.environ.get('SCHIST_IDENTITY'),
|
|
66
|
+
help='(spoke/standalone) Identity name (or set SCHIST_IDENTITY)')
|
|
67
|
+
p_init.add_argument('--hub-path', dest='hub_path',
|
|
68
|
+
help='(hub) Path to the bare repo to create')
|
|
69
|
+
p_init.add_argument('--name', help='(hub/standalone) Vault name for vault.yaml')
|
|
70
|
+
p_init.add_argument('--participant', action='append',
|
|
71
|
+
help='(hub) Participant name (repeatable)')
|
|
72
|
+
|
|
73
|
+
# sync
|
|
74
|
+
p_sync = sub.add_parser('sync', help='Sync spoke vault with hub')
|
|
75
|
+
sync_sub = p_sync.add_subparsers(dest='sync_action')
|
|
76
|
+
sync_sub.add_parser('pull', help='Pull updates from hub')
|
|
77
|
+
sync_sub.add_parser('push', help='Push local changes to hub')
|
|
78
|
+
|
|
79
|
+
args = parser.parse_args()
|
|
80
|
+
|
|
81
|
+
if not args.command:
|
|
82
|
+
parser.print_help()
|
|
83
|
+
sys.exit(1)
|
|
84
|
+
|
|
85
|
+
# init: all modes (hub, spoke, standalone) routed through one helper so
|
|
86
|
+
# the conflict matrix lives in one place.
|
|
87
|
+
if args.command == 'init':
|
|
88
|
+
sync._dispatch_init(args)
|
|
89
|
+
sys.exit(0)
|
|
90
|
+
|
|
91
|
+
vault_path = args.vault
|
|
92
|
+
if not vault_path:
|
|
93
|
+
print('Error: --vault required or set SCHIST_VAULT_PATH', file=sys.stderr)
|
|
94
|
+
sys.exit(1)
|
|
95
|
+
|
|
96
|
+
db_path = args.db or os.path.join(vault_path, '.schist', 'schist.db')
|
|
97
|
+
|
|
98
|
+
# sync sub-dispatch
|
|
99
|
+
if args.command == 'sync':
|
|
100
|
+
if args.sync_action == 'pull':
|
|
101
|
+
sync.sync_pull(args, vault_path, db_path)
|
|
102
|
+
elif args.sync_action == 'push':
|
|
103
|
+
sync.sync_push(args, vault_path, db_path)
|
|
104
|
+
else:
|
|
105
|
+
print('Usage: schist sync {pull|push}', file=sys.stderr)
|
|
106
|
+
sys.exit(1)
|
|
107
|
+
sys.exit(0)
|
|
108
|
+
|
|
109
|
+
dispatch = {
|
|
110
|
+
'add': commands.add,
|
|
111
|
+
'link': commands.link,
|
|
112
|
+
'search': commands.search,
|
|
113
|
+
'query': commands.query,
|
|
114
|
+
'build': commands.build,
|
|
115
|
+
'context': commands.context,
|
|
116
|
+
'schema': commands.schema,
|
|
117
|
+
}
|
|
118
|
+
dispatch[args.command](args, vault_path, db_path)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
if __name__ == '__main__':
|
|
122
|
+
main()
|