Pick a driver. You only need one, but the course shows both because they teach different halves of the idea.
The lab code
git clone https://github.com/brianbaldock/graph-engineering-course
cd graph-engineering-course/labs
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
Check it works:
.venv/bin/python -m pytest tests/ -q
Expected output:
............................ [100%]
50 passed in 0.10s
If those tests pass, every pure-Python lab in this course will run on your machine. Lesson 8 additionally needs an agent driver to wire the MCP server into.
What you just installed
Worth two minutes now, because later lessons say “open graphlab/store.py” without reintroducing it. The whole lab is about 1,200 lines of Python. The graph core (store, validate, extract, ingest, pipeline) is pure standard library; only the policy loader needs PyYAML and the MCP server needs the mcp package, which is why requirements.txt is three lines long:
| File | What it is |
|---|---|
graphlab/store.py |
The graph itself: SQLite schema, add_edge, temporal queries, subgraph retrieval. |
graphlab/validate.py |
The validation gate. Hand-written predicates that decide what may enter the graph. |
graphlab/extract.py |
Turns raw text into candidate entities and edges. Regex by default, no API key needed. |
graphlab/ingest.py |
The single ingestion boundary. Both the pipeline and the MCP server go through it. |
graphlab/pipeline.py |
End-to-end run: read episodes, extract, validate, write, report. |
graphlab/policy.py |
Loads routing_policy.yaml and enforces the retrieval caps. |
graphlab/sample_data.py |
The five-episode sample corpus, plus known people and aliases. |
mcp_server.py |
Exposes the graph to an agent over MCP, with four policy-bounded tools. |
routing_policy.yaml |
Which model does what, and the caps the code actually enforces. |
One term the rest of the course leans on constantly: an episode is one raw source input the graph learned from, stored whole with its own timestamp and never rewritten. A meeting note, a commit message, a document. Edges point back to the episode that produced them, which is what makes a claim auditable rather than a bare assertion. The sample corpus has five of them, which is why the pipeline reports episodes: 5.
Driver A: GitHub Copilot CLI
Best if you want to feel the routing idea. One binary, many models, one subscription.
Install it (full instructions):
# any platform, via npm
npm install -g @github/copilot
# or macOS and Linux, via the install script
curl -fsSL https://gh.io/copilot-install | bash
Copilot CLI needs an active Copilot subscription and authenticates with your existing GitHub credentials. Confirm it landed:
copilot --version
gh auth status # Copilot inherits GitHub auth
Model selection is a flag, which is exactly the lever this course is about:
# cheap, mechanical work: read-only tools, nothing else available
copilot -p "Summarize labs/graphlab/validate.py in five bullets" \
--model claude-haiku-4.5 \
--available-tools='view,grep,glob'
# expensive, high-judgment work: still read-only
copilot -p "Critique the validation gate in labs/graphlab/validate.py. \
What class of bad extraction still gets through?" \
--model claude-opus-4.8 --effort high \
--available-tools='view,grep,glob'
-p mode Copilot cannot stop and ask, so an unapproved tool call hangs at a prompt nobody will answer. The usual advice is --allow-all-tools, and that is the blunt instrument: it hands the agent every tool it currently has, including shell and file writes. Prefer scoping instead. --available-tools limits what exists at all, --allow-tool pre-approves specific tools and takes precedence over --allow-all-tools, and --deny-tool subtracts. Run copilot --help and read the permission flags before you paste an allow-all example into anything you care about. Reserve --allow-all-tools for a disposable directory or a sandbox, and know that is what you are choosing.
There is no copilot models subcommand, and asking a model to list its own availability is not verification. Use auto and let Copilot pick, then check what it selected:
copilot -p "list available models" --model auto --available-tools='view'
Model availability is account-specific and changes. Treat any model list in this course as “what worked on the author’s account when the lesson was written,” and confirm against your own before building a policy on it.
Driver B: Hermes Agent
Best if you want durable memory and MCP tools present in every conversation, without re-wiring per session.
Install it (full instructions):
# Linux, macOS, WSL2, Termux
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
# Windows, in PowerShell
iex (irm https://hermes-agent.nousresearch.com/install.ps1)
On Windows or macOS you can instead run the Hermes Desktop installer, which sets up both the desktop app and the CLI. After installing, hermes setup walks you through connecting a model.
Hermes has a native MCP client. Servers listed in ~/.hermes/config.yaml are connected at startup, their tools discovered, and those tools injected into every platform toolset:
mcp_servers:
graphlab:
command: "/absolute/path/to/labs/.venv/bin/python"
args: ["/absolute/path/to/labs/mcp_server.py"]
env:
GRAPHLAB_DB: "/absolute/path/to/labs/memory.db"
timeout: 60
Tools land in the registry as mcp__{server}__{tool} (two underscores on each side of the server name), so the four tools you’ll build become mcp__graphlab__search_entities, mcp__graphlab__get_subgraph, mcp__graphlab__add_knowledge, and mcp__graphlab__graph_stats.
Two things to know before Lesson 8:
- Restart is required. There’s no hot-reload for MCP servers. Add config, restart the agent.
- The environment is filtered. Hermes does not pass your whole shell environment to MCP subprocesses. On Linux and macOS only
PATH,HOME,USER,LANG,LC_ALL,TERM,SHELLandTMPDIRare inherited (a further set of Windows location variables is allowed on Windows). Anything else, including API keys, must be named explicitly underenv:. That’s a deliberate credential-leak guard, and it’s the reasonGRAPHLAB_DBappears above.
Use absolute paths everywhere
MCP servers are launched as subprocesses with a working directory you do not control. Every path in an MCP config must be absolute. This is the single most common setup failure, in both drivers.
Get yours:
cd graph-engineering-course/labs && pwd
Optional: the production track
Only needed for Lesson 10. Skip it for now.
- Docker, for Neo4j
uv, for running the Graphiti MCP server- An
ANTHROPIC_API_KEYorOPENAI_API_KEYif you want real LLM extraction instead of the deterministic offline one
Everything in Parts 1 through 3 runs free and offline.
Next: what a knowledge graph actually buys you that a vector store doesn’t.
Questions and feedback
Stuck on this lesson, spotted an error, or got it working? Sign in with a GitHub account to ask or comment. Threads live as GitHub Discussions on the course repo, so answers stay findable for the next person.