Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ No setup required — runs entirely in-browser using the embedded engine:
| 03 · LangGraph agent over graph | [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/structured-world/coordinode-python/blob/main/demo/notebooks/03_langgraph_agent.ipynb) |

> Start with **00** to seed the graph — the other notebooks read from it.
> The first cell installs `coordinode-embedded` from source (~8 min); subsequent runs are instant.
> The first cell installs pre-built wheels from PyPI (~30 sec).

## Quick Start

Expand Down
145 changes: 26 additions & 119 deletions demo/notebooks/00_seed_data.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,7 @@
"id": "0",
"metadata": {},
"source": [
"# Seed Demo Data\n",
"\n",
"[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/structured-world/coordinode-python/blob/main/demo/notebooks/00_seed_data.ipynb)\n",
"\n",
"Populates CoordiNode with a **tech industry knowledge graph**.\n",
"\n",
"> **Note:** Embedded mode writes to `COORDINODE_EMBEDDED_PATH` (default\n",
"> `/content/coordinode-demo.db` in Colab, the OS temp dir locally), so\n",
"> the seeded graph persists across cell reruns and is visible to sibling demo\n",
"> notebooks within the same runtime. Delete the file or set a different path to\n",
"> reset. Connecting to a real CoordiNode server via `COORDINODE_ADDR` is also\n",
"> supported.\n",
"\n",
"**Graph contents:**\n",
"- 10 people (engineers, researchers, founders)\n",
"- 6 companies\n",
"- 8 technologies / research areas\n",
"- ~35 relationships (WORKS_AT, FOUNDED, KNOWS, RESEARCHES, INVENTED, ACQUIRED, USES, \u2026)\n",
"\n",
"All nodes carry a `demo=true` property and a `demo_tag` equal to the `DEMO_TAG` variable\n",
"set in the seed cell. MERGE operations and cleanup are scoped to that tag, so only nodes\n",
"with the matching `demo_tag` are written or removed.\n",
"\n",
"**Environments:**\n",
"- **Google Colab** \u2014 uses `coordinode-embedded` (in-process Rust engine, no server needed). First run compiles from source (~5 min); subsequent runs use the pip cache.\n",
"- **Local / Docker Compose** \u2014 connects to a running CoordiNode server via gRPC.\n",
"\n",
"> **\u26a0\ufe0f Note for real-server use:** All writes and the cleanup step are scoped to `demo_tag`.\n",
"> Collisions can occur if multiple runs reuse the same `demo_tag` value or if `demo_tag` is\n",
"> empty. Run against a fresh/empty database or choose a unique `demo_tag` to avoid affecting\n",
"> unrelated nodes."
"# Seed Demo Data\n\n[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/structured-world/coordinode-python/blob/main/demo/notebooks/00_seed_data.ipynb)\n\nPopulates CoordiNode with a **tech industry knowledge graph**.\n\n> **Note:** Embedded mode writes to `COORDINODE_EMBEDDED_PATH` (default\n> `/content/coordinode-demo.db` in Colab, the OS temp dir locally), so\n> the seeded graph persists across cell reruns and is visible to sibling demo\n> notebooks within the same runtime. Delete the file or set a different path to\n> reset. Connecting to a real CoordiNode server via `COORDINODE_ADDR` is also\n> supported.\n\n**Graph contents:**\n- 10 people (engineers, researchers, founders)\n- 6 companies\n- 8 technologies / research areas\n- ~35 relationships (WORKS_AT, FOUNDED, KNOWS, RESEARCHES, INVENTED, ACQUIRED, USES, …)\n\nAll nodes carry a `demo=true` property and a `demo_tag` equal to the `DEMO_TAG` variable\nset in the seed cell. MERGE operations and cleanup are scoped to that tag, so only nodes\nwith the matching `demo_tag` are written or removed.\n\n**Environments:**\n- **Google Colab** — uses `coordinode-embedded` (in-process Rust engine, no server needed). Installs pre-built wheel from PyPI (~30 sec).\n- **Local / Docker Compose** — connects to a running CoordiNode server via gRPC.\n\n> **⚠️ Note for real-server use:** All writes and the cleanup step are scoped to `demo_tag`.\n> Collisions can occur if multiple runs reuse the same `demo_tag` value or if `demo_tag` is\n> empty. Run against a fresh/empty database or choose a unique `demo_tag` to avoid affecting\n> unrelated nodes."
]
},
{
Expand All @@ -57,84 +27,21 @@
"\n",
"IN_COLAB = \"google.colab\" in sys.modules\n",
"\n",
"# Install coordinode-embedded only when running in Colab AND no gRPC server is configured.\n",
"# If COORDINODE_ADDR is set, a live server is already available \u2014 skip the 5-min Rust build.\n",
"pkgs = [\"coordinode\", \"nest_asyncio\"]\n",
"if IN_COLAB and not os.environ.get(\"COORDINODE_ADDR\"):\n",
" # Install Rust toolchain via rustup (https://rustup.rs).\n",
" # Colab's apt packages ship rustc \u22641.75, which cannot build coordinode-embedded\n",
" # (requires Rust \u22651.80 for maturin/pyo3). apt-get is not a viable alternative here.\n",
" # Download the installer to a temp file and execute it explicitly \u2014 this avoids\n",
" # piping remote content directly into a shell while maintaining HTTPS/TLS security\n",
" # through Python's default ssl context (cert-verified, TLS 1.2+).\n",
" # SHA256 pinning of rustup-init is intentionally omitted: rustup.rs does not\n",
" # publish a stable per-release checksum for sh.rustup.rs itself (only for\n",
" # platform-specific rustup-init binaries), and pinning a hash here would break\n",
" # silently on every rustup release. The HTTPS/TLS verification + temp-file\n",
" # execution (not piped to shell) is the rustup team's recommended trust model.\n",
" # No additional env-var gate (e.g. COORDINODE_ENABLE_RUSTUP) is needed:\n",
" # the `IN_COLAB and not COORDINODE_ADDR` check above already ensures this block\n",
" # never runs when a live gRPC server is available, so there is no risk of\n",
" # unintentional execution in local or server environments.\n",
" # Security note: downloading rustup-init via HTTPS with cert verification and\n",
" # executing from a temp file (not piped to shell) is by design \u2014 this is the\n",
" # rustup project's own recommended install method for automated environments.\n",
" # protoc is required by coordinode-raft build (prost-build). Skip if already present (faster reruns),\n",
" # otherwise refresh apt indexes first \u2014 Colab caches can go stale on long-lived runtimes.\n",
" if subprocess.run([\"which\", \"protoc\"], capture_output=True).returncode != 0:\n",
" subprocess.run([\"apt-get\", \"update\", \"-y\", \"-q\"], check=True, timeout=120)\n",
" subprocess.run([\"apt-get\", \"install\", \"-y\", \"-q\", \"protobuf-compiler\"], check=True, timeout=120)\n",
" import ssl as _ssl, tempfile as _tmp, urllib.request as _ur\n",
" pkgs = [\"coordinode-embedded\"] + pkgs\n",
"\n",
" _ctx = _ssl.create_default_context()\n",
" with _tmp.NamedTemporaryFile(mode=\"wb\", suffix=\".sh\", delete=False) as _f:\n",
" with _ur.urlopen(\"https://sh.rustup.rs\", context=_ctx, timeout=30) as _r:\n",
" _f.write(_r.read())\n",
" _rustup_path = _f.name\n",
" try:\n",
" subprocess.run([\"/bin/sh\", _rustup_path, \"-y\", \"-q\"], check=True, timeout=300)\n",
" finally:\n",
" os.unlink(_rustup_path)\n",
" # Add cargo to PATH so maturin/pip can find it.\n",
" _cargo_bin = os.path.expanduser(\"~/.cargo/bin\")\n",
" os.environ[\"PATH\"] = f\"{_cargo_bin}{os.pathsep}{os.environ.get('PATH', '')}\"\n",
" subprocess.run([sys.executable, \"-m\", \"pip\", \"install\", \"-q\", \"maturin\"], check=True, timeout=300)\n",
" subprocess.run(\n",
" [\n",
" sys.executable,\n",
" \"-m\",\n",
" \"pip\",\n",
" \"install\",\n",
" \"-q\",\n",
" \"git+https://github.com/structured-world/coordinode-python.git@50ddc08a89a21fca73be007cb22b57a0054225c3#subdirectory=coordinode-embedded\",\n",
" ],\n",
" check=True,\n",
" timeout=600,\n",
" )\n",
"\n",
"_coordinode_spec = (\n",
" \"git+https://github.com/structured-world/coordinode-python.git@50ddc08a89a21fca73be007cb22b57a0054225c3#subdirectory=coordinode\"\n",
" if IN_COLAB\n",
" else \"coordinode\"\n",
")\n",
"subprocess.run(\n",
" [\n",
" sys.executable,\n",
" \"-m\",\n",
" \"pip\",\n",
" \"install\",\n",
" \"-q\",\n",
" _coordinode_spec,\n",
" \"nest_asyncio\",\n",
" ],\n",
" [sys.executable, \"-m\", \"pip\", \"install\", \"-q\"] + pkgs,\n",
" check=True,\n",
" timeout=300,\n",
" timeout=120,\n",
")\n",
"\n",
"import nest_asyncio\n",
"\n",
"nest_asyncio.apply()\n",
"\n",
"print(\"Ready\")"
"print(\"Ready\")\n"
]
},
{
Expand All @@ -144,8 +51,8 @@
"source": [
"## Connect to CoordiNode\n",
"\n",
"- **Colab**: uses `LocalClient(COORDINODE_EMBEDDED_PATH)` \u2014 in-process embedded engine backed by a file under `/content/`, no server required.\n",
"- **Local with server**: set `COORDINODE_ADDR=host:port` to point at a running CoordiNode (no auto-probe \u2014 explicit only).\n",
"- **Colab**: uses `LocalClient(COORDINODE_EMBEDDED_PATH)` in-process embedded engine backed by a file under `/content/`, no server required.\n",
"- **Local with server**: set `COORDINODE_ADDR=host:port` to point at a running CoordiNode (no auto-probe explicit only).\n",
"- **Local without server**: uses `coordinode-embedded` (file-backed at `COORDINODE_EMBEDDED_PATH`, defaulting to the OS temp dir). Raises `RuntimeError` with install instructions if the package is missing."
]
},
Expand Down Expand Up @@ -178,7 +85,7 @@
" raise RuntimeError(f\"Health check failed for {COORDINODE_ADDR}\")\n",
" print(f\"Connected to {COORDINODE_ADDR}\")\n",
"else:\n",
" # No explicit server \u2014 use the embedded in-process engine backed by a file\n",
" # No explicit server use the embedded in-process engine backed by a file\n",
" # so the graph persists across cell reruns and between sibling demo\n",
" # notebooks within the same runtime.\n",
" try:\n",
Expand All @@ -202,7 +109,7 @@
"id": "5",
"metadata": {},
"source": [
"## Step 1 \u2014 Clear previous demo data"
"## Step 1 Clear previous demo data"
]
},
{
Expand All @@ -226,7 +133,7 @@
"print(\"Using DEMO_TAG:\", DEMO_TAG)\n",
"# Remove prior demo nodes and any attached relationships in one step to avoid\n",
"# duplicate relationship matches during cleanup (undirected MATCH -[r]-() returns\n",
"# each edge twice \u2014 once per endpoint \u2014 causing duplicate-delete errors).\n",
"# each edge twice once per endpoint causing duplicate-delete errors).\n",
"client.cypher(\n",
" \"MATCH (n {demo: true, demo_tag: $tag}) DETACH DELETE n\",\n",
" params={\"tag\": DEMO_TAG},\n",
Expand All @@ -239,7 +146,7 @@
"id": "7",
"metadata": {},
"source": [
"## Step 2 \u2014 Create nodes"
"## Step 2 Create nodes"
]
},
{
Expand All @@ -249,13 +156,13 @@
"metadata": {},
"outputs": [],
"source": [
"# \u2500\u2500 People \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n",
"# ── People ────────────────────────────────────────────────────────────────\n",
"people = [\n",
" {\"name\": \"Alice Chen\", \"role\": \"ML Researcher\", \"org\": \"DeepMind\", \"field\": \"Reinforcement Learning\"},\n",
" {\"name\": \"Bob Torres\", \"role\": \"Staff Engineer\", \"org\": \"Google\", \"field\": \"Distributed Systems\"},\n",
" {\"name\": \"Carol Smith\", \"role\": \"Founder & CEO\", \"org\": \"Synthex\", \"field\": \"NLP\"},\n",
" {\"name\": \"David Park\", \"role\": \"Research Scientist\", \"org\": \"OpenAI\", \"field\": \"LLMs\"},\n",
" {\"name\": \"Eva M\u00fcller\", \"role\": \"Systems Architect\", \"org\": \"Synthex\", \"field\": \"Graph Databases\"},\n",
" {\"name\": \"Eva Müller\", \"role\": \"Systems Architect\", \"org\": \"Synthex\", \"field\": \"Graph Databases\"},\n",
" {\"name\": \"Frank Liu\", \"role\": \"Principal Engineer\", \"org\": \"Meta\", \"field\": \"Graph ML\"},\n",
" {\"name\": \"Grace Okafor\", \"role\": \"PhD Researcher\", \"org\": \"MIT\", \"field\": \"Knowledge Graphs\"},\n",
" {\"name\": \"Henry Rossi\", \"role\": \"CTO\", \"org\": \"Synthex\", \"field\": \"Databases\"},\n",
Expand All @@ -272,7 +179,7 @@
"\n",
"print(f\"Created {len(people)} people\")\n",
"\n",
"# \u2500\u2500 Companies \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n",
"# ── Companies ─────────────────────────────────────────────────────────────\n",
"companies = [\n",
" {\"name\": \"Google\", \"industry\": \"Technology\", \"founded\": 1998, \"hq\": \"Mountain View\"},\n",
" {\"name\": \"Meta\", \"industry\": \"Technology\", \"founded\": 2004, \"hq\": \"Menlo Park\"},\n",
Expand All @@ -290,7 +197,7 @@
"\n",
"print(f\"Created {len(companies)} companies\")\n",
"\n",
"# \u2500\u2500 Technologies \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n",
"# ── Technologies ──────────────────────────────────────────────────────────\n",
"technologies = [\n",
" {\"name\": \"Transformer\", \"type\": \"Architecture\", \"year\": 2017},\n",
" {\"name\": \"Graph Neural Network\", \"type\": \"Algorithm\", \"year\": 2009},\n",
Expand All @@ -316,7 +223,7 @@
"id": "9",
"metadata": {},
"source": [
"## Step 3 \u2014 Create relationships"
"## Step 3 Create relationships"
]
},
{
Expand All @@ -332,7 +239,7 @@
" (\"Bob Torres\", \"WORKS_AT\", \"Google\", {}),\n",
" (\"Carol Smith\", \"WORKS_AT\", \"Synthex\", {\"since\": 2021}),\n",
" (\"David Park\", \"WORKS_AT\", \"OpenAI\", {}),\n",
" (\"Eva M\u00fcller\", \"WORKS_AT\", \"Synthex\", {\"since\": 2022}),\n",
" (\"Eva Müller\", \"WORKS_AT\", \"Synthex\", {\"since\": 2022}),\n",
" (\"Frank Liu\", \"WORKS_AT\", \"Meta\", {}),\n",
" (\"Grace Okafor\", \"WORKS_AT\", \"MIT\", {}),\n",
" (\"Henry Rossi\", \"WORKS_AT\", \"Synthex\", {\"since\": 2021}),\n",
Expand All @@ -347,7 +254,7 @@
" (\"Carol Smith\", \"KNOWS\", \"Bob Torres\", {}),\n",
" (\"Grace Okafor\", \"KNOWS\", \"Alice Chen\", {}),\n",
" (\"Frank Liu\", \"KNOWS\", \"James Wright\", {}),\n",
" (\"Eva M\u00fcller\", \"KNOWS\", \"Grace Okafor\", {}),\n",
" (\"Eva Müller\", \"KNOWS\", \"Grace Okafor\", {}),\n",
" # RESEARCHES / WORKS_ON\n",
" (\"Alice Chen\", \"RESEARCHES\", \"Reinforcement Learning\", {\"since\": 2019}),\n",
" (\"David Park\", \"RESEARCHES\", \"LLM\", {\"since\": 2020}),\n",
Expand Down Expand Up @@ -405,7 +312,7 @@
"id": "11",
"metadata": {},
"source": [
"## Step 4 \u2014 Verify"
"## Step 4 Verify"
]
},
{
Expand Down Expand Up @@ -450,7 +357,7 @@
" params={\"co\": \"Synthex\", \"tag\": DEMO_TAG},\n",
")\n",
"for r in rows:\n",
" print(f\" {r['name']} \u2014 {r['role']}\")\n",
" print(f\" {r['name']} {r['role']}\")\n",
"\n",
"print(\"\\n=== What does Synthex use? ===\")\n",
"rows = client.cypher(\n",
Expand All @@ -466,11 +373,11 @@
" params={\"tech\": \"GraphRAG\", \"tag\": DEMO_TAG},\n",
")\n",
"for r in rows:\n",
" print(f\" \u2192 {r['dependency']}\")\n",
" print(f\" {r['dependency']}\")\n",
"\n",
"print(\"\\n\u2713 Demo data seeded.\")\n",
"print(\"To query it from notebooks 01\u201303:\")\n",
"print(f\" - Embedded mode: open them with the same COORDINODE_EMBEDDED_PATH (this run: {COORDINODE_EMBEDDED_PATH}) \u2014 they will see this seeded graph.\")\n",
"print(\"\\n Demo data seeded.\")\n",
"print(\"To query it from notebooks 01–03:\")\n",
"print(f\" - Embedded mode: open them with the same COORDINODE_EMBEDDED_PATH (this run: {COORDINODE_EMBEDDED_PATH}) they will see this seeded graph.\")\n",
"print(\" - Server mode: point them at the same running CoordiNode via COORDINODE_ADDR.\")\n",
"client.close()"
]
Expand All @@ -488,4 +395,4 @@
},
"nbformat": 4,
"nbformat_minor": 5
}
}
Loading
Loading