Skip to content

Commit a95c513

Browse files
committed
feat: initial Python SDK for CoordiNode
Three packages: - coordinode: core gRPC client (sync + async) - langchain-coordinode: GraphStore + GraphCypherQAChain support - llama-index-graph-stores-coordinode: PropertyGraphStore with vector queries Proto stubs generated from coordinode-proto-ce submodule via make proto. Versioning via hatch-vcs (git tags → PEP 440 version). CI: lint + unit tests (3.9/3.11/3.12) + integration tests against Docker image. Release: tag v0.3.0a1 → TestPyPI, tag v0.3.0 → PyPI (OIDC trusted publisher).
0 parents  commit a95c513

26 files changed

Lines changed: 1777 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
jobs:
9+
lint:
10+
name: Lint
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- uses: actions/setup-python@v5
16+
with:
17+
python-version: "3.11"
18+
19+
- run: pip install ruff
20+
- run: ruff check coordinode/ langchain-coordinode/ llama-index-coordinode/ tests/
21+
- run: ruff format --check coordinode/ langchain-coordinode/ llama-index-coordinode/ tests/
22+
23+
test:
24+
name: Test (Python ${{ matrix.python-version }})
25+
runs-on: ubuntu-latest
26+
strategy:
27+
matrix:
28+
python-version: ["3.9", "3.11", "3.12"]
29+
steps:
30+
- uses: actions/checkout@v4
31+
with:
32+
submodules: recursive
33+
34+
- uses: actions/setup-python@v5
35+
with:
36+
python-version: ${{ matrix.python-version }}
37+
38+
- name: Install protoc
39+
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler
40+
41+
- name: Install packages
42+
run: |
43+
pip install grpcio-tools
44+
pip install -e "coordinode[dev]"
45+
pip install -e langchain-coordinode/
46+
pip install -e llama-index-coordinode/
47+
48+
- name: Generate proto stubs
49+
run: make proto
50+
51+
- name: Unit tests
52+
run: pytest tests/unit/ -v
53+
54+
test-integration:
55+
name: Integration tests
56+
runs-on: ubuntu-latest
57+
services:
58+
coordinode:
59+
image: ghcr.io/structured-world/coordinode:latest
60+
ports:
61+
- 7080:7080
62+
- 7084:7084
63+
options: >-
64+
--health-cmd "wget -qO- http://localhost:7084/health || exit 1"
65+
--health-interval 10s
66+
--health-timeout 5s
67+
--health-retries 12
68+
steps:
69+
- uses: actions/checkout@v4
70+
with:
71+
submodules: recursive
72+
73+
- uses: actions/setup-python@v5
74+
with:
75+
python-version: "3.11"
76+
77+
- name: Install protoc
78+
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler
79+
80+
- name: Install + generate proto
81+
run: |
82+
pip install grpcio-tools
83+
pip install -e "coordinode[dev]"
84+
make proto
85+
86+
- name: Integration tests
87+
env:
88+
COORDINODE_ADDR: "localhost:7080"
89+
run: pytest tests/integration/ -v --timeout=30

.github/workflows/release.yml

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
name: Release
2+
3+
# Triggered manually: create a tag v0.3.0 → GitHub Release → this workflow publishes to PyPI.
4+
# Tag format: v{MAJOR}.{MINOR}.{PATCH} → stable, publishes to PyPI
5+
# v{MAJOR}.{MINOR}.{PATCH}a{N} → pre-release, publishes to TestPyPI only
6+
7+
on:
8+
push:
9+
tags:
10+
- "v[0-9]+.[0-9]+.[0-9]+*"
11+
12+
permissions:
13+
contents: write
14+
15+
jobs:
16+
build:
17+
name: Build ${{ matrix.package.name }}
18+
runs-on: ubuntu-latest
19+
strategy:
20+
matrix:
21+
package:
22+
- name: coordinode
23+
path: coordinode
24+
- name: langchain-coordinode
25+
path: langchain-coordinode
26+
- name: llama-index-graph-stores-coordinode
27+
path: llama-index-coordinode
28+
steps:
29+
- uses: actions/checkout@v4
30+
with:
31+
submodules: recursive
32+
fetch-depth: 0 # hatch-vcs needs full history for tag detection
33+
34+
- uses: actions/setup-python@v5
35+
with:
36+
python-version: "3.11"
37+
38+
- name: Install protoc + build tools
39+
run: |
40+
sudo apt-get update && sudo apt-get install -y protobuf-compiler
41+
pip install hatchling hatch-vcs grpcio-tools build
42+
43+
- name: Generate proto stubs (coordinode only)
44+
if: matrix.package.name == 'coordinode'
45+
run: make proto
46+
47+
- name: Build wheel + sdist
48+
working-directory: ${{ matrix.package.path }}
49+
run: python -m build
50+
51+
- name: Upload dist artifact
52+
uses: actions/upload-artifact@v4
53+
with:
54+
name: dist-${{ matrix.package.name }}
55+
path: ${{ matrix.package.path }}/dist/
56+
retention-days: 1
57+
58+
publish-testpypi:
59+
name: Publish to TestPyPI (pre-release)
60+
runs-on: ubuntu-latest
61+
needs: build
62+
if: contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc')
63+
environment: testpypi
64+
permissions:
65+
id-token: write
66+
strategy:
67+
matrix:
68+
package:
69+
- coordinode
70+
- langchain-coordinode
71+
- llama-index-graph-stores-coordinode
72+
steps:
73+
- uses: actions/download-artifact@v4
74+
with:
75+
name: dist-${{ matrix.package }}
76+
path: dist/
77+
78+
- uses: pypa/gh-action-pypi-publish@release/v1
79+
with:
80+
repository-url: https://test.pypi.org/legacy/
81+
packages-dir: dist/
82+
83+
publish-pypi:
84+
name: Publish to PyPI (stable)
85+
runs-on: ubuntu-latest
86+
needs: build
87+
if: "!contains(github.ref_name, 'a') && !contains(github.ref_name, 'b') && !contains(github.ref_name, 'rc')"
88+
environment: pypi
89+
permissions:
90+
id-token: write
91+
strategy:
92+
matrix:
93+
package:
94+
- coordinode
95+
- langchain-coordinode
96+
- llama-index-graph-stores-coordinode
97+
steps:
98+
- uses: actions/download-artifact@v4
99+
with:
100+
name: dist-${{ matrix.package }}
101+
path: dist/
102+
103+
- uses: pypa/gh-action-pypi-publish@release/v1
104+
with:
105+
packages-dir: dist/
106+
107+
github-release:
108+
name: Create GitHub Release
109+
runs-on: ubuntu-latest
110+
needs: build
111+
permissions:
112+
contents: write
113+
steps:
114+
- uses: actions/download-artifact@v4
115+
with:
116+
pattern: dist-*
117+
merge-multiple: true
118+
path: dist/
119+
120+
- uses: softprops/action-gh-release@v2
121+
with:
122+
prerelease: ${{ contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc') }}
123+
generate_release_notes: true
124+
files: dist/*

.gitignore

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Generated proto stubs — run `make proto` to regenerate
2+
coordinode/_proto/coordinode/
3+
4+
# Build artifacts
5+
dist/
6+
*.egg-info/
7+
__pycache__/
8+
*.pyc
9+
*.pyo
10+
.pytest_cache/
11+
.ruff_cache/
12+
.mypy_cache/
13+
14+
# Virtual envs
15+
.venv/
16+
venv/
17+
env/
18+
19+
# Version files generated by hatch-vcs
20+
coordinode/_version.py
21+
langchain_coordinode/_version.py
22+
llama_index/graph_stores/coordinode/_version.py

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "proto"]
2+
path = proto
3+
url = https://github.com/structured-world/coordinode-proto-ce.git

Makefile

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
.PHONY: proto proto-check install test test-unit test-integration lint clean
2+
3+
PROTO_SRC := proto
4+
PROTO_OUT := coordinode/_proto
5+
6+
# Generate gRPC stubs from proto submodule into coordinode/_proto/
7+
proto:
8+
@echo "==> Generating proto stubs..."
9+
@mkdir -p $(PROTO_OUT)
10+
python -m grpc_tools.protoc \
11+
-I$(PROTO_SRC) \
12+
--python_out=$(PROTO_OUT) \
13+
--grpc_python_out=$(PROTO_OUT) \
14+
--pyi_out=$(PROTO_OUT) \
15+
$$(find $(PROTO_SRC) -name '*.proto')
16+
@# Add __init__.py to every generated package directory
17+
@find $(PROTO_OUT) -type d -exec touch {}/__init__.py \;
18+
@# Fix relative imports in generated *_pb2_grpc.py files (grpc_tools generates absolute)
19+
@find $(PROTO_OUT) -name '*_pb2_grpc.py' -exec sed -i '' \
20+
's/^from coordinode\./from coordinode._proto.coordinode./g' {} \;
21+
@echo "==> Proto generation complete: $(PROTO_OUT)/"
22+
23+
proto-check:
24+
@test -f $(PROTO_OUT)/coordinode/v1/query/cypher_pb2.py || \
25+
(echo "ERROR: Proto stubs not generated. Run: make proto" && exit 1)
26+
27+
# Install all packages in editable mode for development
28+
install: proto
29+
pip install -e "coordinode[dev]"
30+
pip install -e langchain-coordinode/
31+
pip install -e llama-index-coordinode/
32+
33+
test: proto-check test-unit
34+
35+
test-unit:
36+
pytest tests/unit/ -v
37+
38+
test-integration:
39+
pytest tests/integration/ -v --timeout=30
40+
41+
lint:
42+
ruff check coordinode/ langchain-coordinode/ llama-index-coordinode/ tests/
43+
ruff format --check coordinode/ langchain-coordinode/ llama-index-coordinode/ tests/
44+
45+
clean:
46+
rm -rf $(PROTO_OUT)/coordinode
47+
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
48+
find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
49+
find . -type d -name dist -exec rm -rf {} + 2>/dev/null || true

README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# coordinode-python
2+
3+
Python SDK for [CoordiNode](https://github.com/structured-world/coordinode) — the graph-native hybrid retrieval engine for AI and GraphRAG.
4+
5+
## Packages
6+
7+
| Package | Install | Description |
8+
|---------|---------|-------------|
9+
| `coordinode` | `pip install coordinode` | Core gRPC client |
10+
| `langchain-coordinode` | `pip install langchain-coordinode` | LangChain `GraphStore` + `GraphCypherQAChain` |
11+
| `llama-index-graph-stores-coordinode` | `pip install llama-index-graph-stores-coordinode` | LlamaIndex `PropertyGraphStore` |
12+
13+
## Quick start
14+
15+
```bash
16+
# Start CoordiNode
17+
docker compose up -d
18+
19+
# Install
20+
pip install coordinode
21+
```
22+
23+
```python
24+
from coordinode import CoordinodeClient
25+
26+
with CoordinodeClient("localhost", port=7080) as db:
27+
rows = db.cypher(
28+
"MATCH (n:Concept {name: $name})-[:RELATED_TO*1..2]->(m) RETURN m.name",
29+
params={"name": "machine learning"},
30+
)
31+
for row in rows:
32+
print(row["m.name"])
33+
```
34+
35+
## LangChain
36+
37+
```python
38+
from langchain_coordinode import CoordinodeGraph
39+
from langchain.chains import GraphCypherQAChain
40+
from langchain_openai import ChatOpenAI
41+
42+
graph = CoordinodeGraph("localhost")
43+
chain = GraphCypherQAChain.from_llm(ChatOpenAI(model="gpt-4o-mini"), graph=graph)
44+
result = chain.invoke({"query": "What is related to transformers?"})
45+
```
46+
47+
## LlamaIndex
48+
49+
```python
50+
from llama_index.core import PropertyGraphIndex
51+
from llama_index.graph_stores.coordinode import CoordinodePropertyGraphStore
52+
53+
store = CoordinodePropertyGraphStore("localhost")
54+
index = PropertyGraphIndex.from_documents(docs, property_graph_store=store)
55+
engine = index.as_query_engine()
56+
```
57+
58+
## Development
59+
60+
```bash
61+
git clone --recurse-submodules https://github.com/structured-world/coordinode-python
62+
cd coordinode-python
63+
pip install grpcio-tools
64+
make install # generates proto stubs + installs all packages in editable mode
65+
make test
66+
```
67+
68+
## Versioning
69+
70+
SDK versions track the server: `coordinode 0.3.x` is compatible with `coordinode-server 0.3.x`.
71+
72+
## License
73+
74+
Apache-2.0

0 commit comments

Comments
 (0)