Skip to content

Commit 744f5f6

Browse files
committed
feat: uv workspace + PyPI READMEs + donation QR
uv workspace: - Root pyproject.toml with [tool.uv.workspace] — members: coordinode, langchain-coordinode, llama-index-coordinode - uv.lock committed (89 packages, reproducible installs) - hatch-vcs: fallback-version = "0.0.0" + raw-options root = ".." so git version detection works from subdirectory - Makefile: `make install` now uses `uv sync`; `make install-pip` as pip fallback for non-uv contributors - CI updated: `uv sync` + `uv run` everywhere, no `uv pip install` Both pip and uv work without any wrapper: pip install coordinode # PyPI user uv add coordinode # uv user pip install -e coordinode/ # contributor (pip) uv sync # contributor (uv) READMEs: - Root README.md: badges, all 3 packages, uv+pip quickstart, dev setup (uv + pip), donation section with QR code - coordinode/README.md: PyPI page — connection options, type mapping table, vector search, async client - langchain-coordinode/README.md: PyPI page — GraphCypherQAChain, schema inspection, LLMGraphTransformer, add_graph_documents - llama-index-coordinode/README.md: PyPI page — PropertyGraphIndex from docs + from existing, vector+keyword hybrid retrieval, manual upsert, capabilities table - assets/usdt-qr.svg: USDT TRC-20 donation QR code (TFDsez...) - Sub-package READMEs reference QR via absolute GitHub raw URL (required for PyPI markdown rendering) - readme = "README.md" in each pyproject.toml (PyPI page) python-version classifiers: 3.11, 3.12, 3.13 (3.9/3.10 EOL) requires-python = ">=3.11" in all 3 packages
1 parent 0c246ae commit 744f5f6

12 files changed

Lines changed: 3247 additions & 40 deletions

File tree

.github/workflows/ci.yml

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ jobs:
1616
with:
1717
python-version: "3.11"
1818

19-
- run: uv pip install ruff --system
20-
- run: ruff check coordinode/ langchain-coordinode/ llama-index-coordinode/ tests/
21-
- run: ruff format --check coordinode/ langchain-coordinode/ llama-index-coordinode/ tests/
19+
- run: uv sync
20+
- run: uv run ruff check coordinode/ langchain-coordinode/ llama-index-coordinode/ tests/
21+
- run: uv run ruff format --check coordinode/ langchain-coordinode/ llama-index-coordinode/ tests/
2222

2323
test:
2424
name: Test (Python ${{ matrix.python-version }})
@@ -36,18 +36,14 @@ jobs:
3636
with:
3737
python-version: ${{ matrix.python-version }}
3838

39-
- name: Install packages
40-
run: |
41-
uv pip install grpcio-tools --system
42-
uv pip install -e "coordinode[dev]" --system
43-
uv pip install -e langchain-coordinode/ --system
44-
uv pip install -e llama-index-coordinode/ --system
39+
- name: Install dependencies
40+
run: uv sync
4541

4642
- name: Generate proto stubs
47-
run: make proto
43+
run: uv run make proto
4844

4945
- name: Unit tests
50-
run: pytest tests/unit/ -v
46+
run: uv run pytest tests/unit/ -v
5147

5248
test-integration:
5349
name: Integration tests
@@ -74,11 +70,10 @@ jobs:
7470

7571
- name: Install + generate proto
7672
run: |
77-
uv pip install grpcio-tools --system
78-
uv pip install -e "coordinode[dev]" --system
79-
make proto
73+
uv sync
74+
uv run make proto
8075
8176
- name: Integration tests
8277
env:
8378
COORDINODE_ADDR: "localhost:7080"
84-
run: pytest tests/integration/ -v --timeout=30
79+
run: uv run pytest tests/integration/ -v --timeout=30

Makefile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: proto proto-check install test test-unit test-integration lint clean
1+
.PHONY: proto proto-check install install-uv test test-unit test-integration lint clean
22

33
PROTO_SRC := proto
44
PROTO_OUT := coordinode/_proto
@@ -24,8 +24,12 @@ proto-check:
2424
@test -f $(PROTO_OUT)/coordinode/v1/query/cypher_pb2.py || \
2525
(echo "ERROR: Proto stubs not generated. Run: make proto" && exit 1)
2626

27-
# Install all packages in editable mode for development
27+
# Install using uv (recommended for contributors)
2828
install: proto
29+
uv sync
30+
31+
# Install using pip (alternative — works without uv)
32+
install-pip: proto
2933
pip install -e "coordinode[dev]"
3034
pip install -e langchain-coordinode/
3135
pip install -e llama-index-coordinode/

README.md

Lines changed: 76 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,105 @@
11
# coordinode-python
22

3+
[![CI](https://github.com/structured-world/coordinode-python/actions/workflows/ci.yml/badge.svg)](https://github.com/structured-world/coordinode-python/actions/workflows/ci.yml)
4+
[![PyPI](https://img.shields.io/pypi/v/coordinode)](https://pypi.org/project/coordinode/)
5+
[![Python](https://img.shields.io/pypi/pyversions/coordinode)](https://pypi.org/project/coordinode/)
6+
[![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
7+
38
Python SDK for [CoordiNode](https://github.com/structured-world/coordinode) — the graph-native hybrid retrieval engine for AI and GraphRAG.
49

10+
Graph + Vector + Full-Text in a single transactional engine. One client, one query.
11+
512
## Packages
613

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` |
14+
| Package | PyPI | Description |
15+
|---------|------|-------------|
16+
| [`coordinode`](coordinode/) | [![PyPI](https://img.shields.io/pypi/v/coordinode?label=coordinode)](https://pypi.org/project/coordinode/) | Core gRPC client — sync + async |
17+
| [`langchain-coordinode`](langchain-coordinode/) | [![PyPI](https://img.shields.io/pypi/v/langchain-coordinode?label=langchain-coordinode)](https://pypi.org/project/langchain-coordinode/) | LangChain `GraphStore` + `GraphCypherQAChain` |
18+
| [`llama-index-graph-stores-coordinode`](llama-index-coordinode/) | [![PyPI](https://img.shields.io/pypi/v/llama-index-graph-stores-coordinode?label=llama-index-graph-stores-coordinode)](https://pypi.org/project/llama-index-graph-stores-coordinode/) | LlamaIndex `PropertyGraphStore` |
1219

13-
## Quick start
20+
## Quick Start
1421

1522
```bash
1623
# Start CoordiNode
1724
docker compose up -d
1825

1926
# Install
2027
pip install coordinode
28+
# or
29+
uv add coordinode
2130
```
2231

2332
```python
2433
from coordinode import CoordinodeClient
2534

26-
with CoordinodeClient("localhost", port=7080) as db:
35+
with CoordinodeClient("localhost:7080") as db:
36+
# Cypher query — returns List[Dict[str, Any]]
2737
rows = db.cypher(
28-
"MATCH (n:Concept {name: $name})-[:RELATED_TO*1..2]->(m) RETURN m.name",
38+
"MATCH (n:Concept {name: $name})-[:RELATED_TO*1..2]->(m) RETURN m.name AS name",
2939
params={"name": "machine learning"},
3040
)
3141
for row in rows:
32-
print(row["m.name"])
42+
print(row["name"])
3343
```
3444

35-
## LangChain
45+
## LangChain — GraphRAG Pipeline
3646

3747
```python
3848
from langchain_coordinode import CoordinodeGraph
3949
from langchain.chains import GraphCypherQAChain
4050
from langchain_openai import ChatOpenAI
4151

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?"})
52+
graph = CoordinodeGraph("localhost:7080")
53+
chain = GraphCypherQAChain.from_llm(
54+
ChatOpenAI(model="gpt-4o-mini"),
55+
graph=graph,
56+
verbose=True,
57+
)
58+
result = chain.invoke({"query": "What concepts are related to transformers?"})
59+
print(result["result"])
4560
```
4661

47-
## LlamaIndex
62+
## LlamaIndex — Knowledge Graph Index
4863

4964
```python
5065
from llama_index.core import PropertyGraphIndex
5166
from llama_index.graph_stores.coordinode import CoordinodePropertyGraphStore
5267

53-
store = CoordinodePropertyGraphStore("localhost")
68+
store = CoordinodePropertyGraphStore("localhost:7080")
5469
index = PropertyGraphIndex.from_documents(docs, property_graph_store=store)
55-
engine = index.as_query_engine()
70+
engine = index.as_query_engine(include_text=True)
71+
response = engine.query("Explain attention mechanisms")
72+
```
73+
74+
## Development Setup
75+
76+
### Using uv (recommended)
77+
78+
```bash
79+
git clone --recurse-submodules https://github.com/structured-world/coordinode-python
80+
cd coordinode-python
81+
uv sync # installs all packages + dev deps from uv.lock
82+
make proto # generate gRPC stubs from proto submodule
83+
uv run pytest tests/unit/ -v
5684
```
5785

58-
## Development
86+
### Using pip
5987

6088
```bash
6189
git clone --recurse-submodules https://github.com/structured-world/coordinode-python
6290
cd coordinode-python
6391
pip install grpcio-tools
64-
make install # generates proto stubs + installs all packages in editable mode
65-
make test
92+
make install-pip # generates proto stubs + installs all packages in editable mode
93+
pytest tests/unit/ -v
94+
```
95+
96+
### Running integration tests
97+
98+
Integration tests require a running CoordiNode instance:
99+
100+
```bash
101+
docker compose up -d
102+
COORDINODE_ADDR=localhost:7080 pytest tests/integration/ -v --timeout=30
66103
```
67104

68105
## Versioning
@@ -71,4 +108,23 @@ SDK versions track the server: `coordinode 0.3.x` is compatible with `coordinode
71108

72109
## License
73110

74-
Apache-2.0
111+
Apache-2.0 — see [LICENSE](LICENSE).
112+
113+
---
114+
115+
## Support the Project
116+
117+
If you believe graph + vector + full-text retrieval should live in one engine under a genuine open-source license, consider sponsoring:
118+
119+
- [GitHub Sponsors](https://github.com/sponsors/structured-world)
120+
- [Open Collective](https://opencollective.com/structured-world)
121+
122+
<div align="center">
123+
124+
![USDT TRC-20 Donation QR](assets/usdt-qr.svg)
125+
126+
**USDT (TRC-20):** `TFDsezHa1cBkoeZT5q2T49Wp66K8t2DmdA`
127+
128+
</div>
129+
130+
Sponsorship accelerates: vector search integration, Bolt protocol compatibility, and the Enterprise Edition for horizontal scaling.

assets/usdt-qr.svg

Lines changed: 1 addition & 0 deletions
Loading

coordinode/README.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# coordinode
2+
3+
[![PyPI](https://img.shields.io/pypi/v/coordinode)](https://pypi.org/project/coordinode/)
4+
[![Python](https://img.shields.io/pypi/pyversions/coordinode)](https://pypi.org/project/coordinode/)
5+
[![License](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/structured-world/coordinode-python/blob/main/LICENSE)
6+
[![CI](https://github.com/structured-world/coordinode-python/actions/workflows/ci.yml/badge.svg)](https://github.com/structured-world/coordinode-python/actions/workflows/ci.yml)
7+
8+
Python gRPC client for [CoordiNode](https://github.com/structured-world/coordinode) — the graph-native hybrid retrieval engine for AI and GraphRAG.
9+
10+
## Installation
11+
12+
```bash
13+
pip install coordinode
14+
```
15+
16+
```bash
17+
uv add coordinode
18+
```
19+
20+
## Requirements
21+
22+
- Python 3.11+
23+
- Running CoordiNode instance (`docker compose up -d` or binary)
24+
25+
## Quick Start
26+
27+
```python
28+
from coordinode import CoordinodeClient
29+
30+
# Synchronous client — context manager handles connection lifecycle
31+
with CoordinodeClient("localhost:7080") as db:
32+
# Cypher query — returns List[Dict[str, Any]]
33+
result = db.cypher("RETURN 1 AS n")
34+
print(result) # [{'n': 1}]
35+
36+
# With parameters
37+
rows = db.cypher(
38+
"MATCH (n:Person {name: $name}) RETURN n.age AS age",
39+
params={"name": "Alice"},
40+
)
41+
42+
# Create nodes
43+
db.cypher(
44+
"CREATE (n:Document {title: $title, embedding: $vec})",
45+
params={"title": "RAG intro", "vec": [0.1, 0.2, 0.3, 0.4]},
46+
)
47+
48+
# Health check
49+
assert db.health()
50+
```
51+
52+
## Async Client
53+
54+
```python
55+
import asyncio
56+
from coordinode import AsyncCoordinodeClient
57+
58+
async def main():
59+
async with AsyncCoordinodeClient("localhost:7080") as db:
60+
rows = await db.cypher("MATCH (n:Concept) RETURN n.name AS name LIMIT 5")
61+
for row in rows:
62+
print(row["name"])
63+
64+
asyncio.run(main())
65+
```
66+
67+
## Connection Options
68+
69+
```python
70+
# host:port string
71+
client = CoordinodeClient("localhost:7080")
72+
73+
# Separate host and port
74+
client = CoordinodeClient("localhost", port=7080)
75+
76+
# TLS
77+
client = CoordinodeClient("db.example.com:7443", tls=True)
78+
79+
# Custom timeout (seconds)
80+
client = CoordinodeClient("localhost:7080", timeout=60.0)
81+
```
82+
83+
## Type Mapping
84+
85+
CoordiNode properties map to Python types automatically:
86+
87+
| Python type | CoordiNode type |
88+
|-------------|-----------------|
89+
| `int` | `int_value` |
90+
| `float` | `float_value` |
91+
| `str` | `string_value` |
92+
| `bool` | `bool_value` |
93+
| `bytes` | `bytes_value` |
94+
| `list[float]` | `Vector` (HNSW-indexable) |
95+
| `list[Any]` | `PropertyList` |
96+
| `dict[str, Any]` | `PropertyMap` |
97+
| `None` | unset (null semantics) |
98+
99+
## Vector Search
100+
101+
```python
102+
# Store a node with a vector embedding
103+
db.cypher(
104+
"CREATE (d:Doc {title: $title, embedding: $vec})",
105+
params={"title": "RAG intro", "vec": [0.1] * 384},
106+
)
107+
108+
# Nearest-neighbour search (requires HNSW index — coming in v0.4)
109+
results = db.vector_search(
110+
label="Doc",
111+
property="embedding",
112+
vector=[0.1] * 384,
113+
top_k=10,
114+
metric="cosine", # "cosine" | "l2" | "dot" | "l1"
115+
)
116+
for r in results:
117+
print(r.node.id, r.distance)
118+
```
119+
120+
## Related Packages
121+
122+
| Package | Description |
123+
|---------|-------------|
124+
| [`langchain-coordinode`](https://pypi.org/project/langchain-coordinode/) | LangChain `GraphStore` + `GraphCypherQAChain` |
125+
| [`llama-index-graph-stores-coordinode`](https://pypi.org/project/llama-index-graph-stores-coordinode/) | LlamaIndex `PropertyGraphStore` |
126+
127+
## Links
128+
129+
- [Source](https://github.com/structured-world/coordinode-python)
130+
- [CoordiNode server](https://github.com/structured-world/coordinode)
131+
- [Issues](https://github.com/structured-world/coordinode-python/issues)
132+
- [Changelog](https://github.com/structured-world/coordinode-python/releases)
133+
134+
## Support
135+
136+
<div align="center">
137+
138+
[![USDT TRC-20](https://raw.githubusercontent.com/structured-world/coordinode-python/main/assets/usdt-qr.svg)](https://github.com/sponsors/structured-world)
139+
140+
**USDT (TRC-20):** `TFDsezHa1cBkoeZT5q2T49Wp66K8t2DmdA`
141+
142+
[GitHub Sponsors](https://github.com/sponsors/structured-world) · [Open Collective](https://opencollective.com/structured-world)
143+
144+
</div>
145+
146+
## License
147+
148+
Apache-2.0

coordinode/pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
66
name = "coordinode"
77
dynamic = ["version"]
88
description = "Python client for CoordiNode — graph + vector + full-text database"
9-
readme = "../README.md"
9+
readme = "README.md"
1010
requires-python = ">=3.11"
1111
license = { text = "Apache-2.0" }
1212
authors = [{ name = "structured.world", email = "dev@structured.world" }]
@@ -43,6 +43,8 @@ Issues = "https://github.com/structured-world/coordinode-python/issues"
4343
[tool.hatch.version]
4444
source = "vcs"
4545
tag-pattern = "v(?P<version>.*)"
46+
fallback-version = "0.0.0"
47+
raw-options = {root = ".."}
4648

4749
[tool.hatch.build.hooks.vcs]
4850
version-file = "coordinode/_version.py"

0 commit comments

Comments
 (0)