Step-by-step instructions for running ContextHub as the context engine inside an OpenClaw agent runtime — fully local, no Docker required.
This guide walks through running the full stack:
┌─────────────────────────────────────────────────────────────┐
│ Terminal 1: PostgreSQL (Homebrew service, always on) │
│ Terminal 2: ContextHub Server (FastAPI on :8000) │
│ Terminal 3: Python Sidecar (FastAPI on :9100) │
│ Terminal 4: OpenClaw Gateway (Node.js on :18789) │
│ Terminal 5: OpenClaw TUI (interactive agent chat) │
└─────────────────────────────────────────────────────────────┘
The data flow is:
OpenClaw TUI (you type) ──► OpenClaw Gateway
└─ ContextHubBridge (TS, context-engine plugin)
└─ HTTP ──► Python Sidecar (:9100)
└─ ContextHubContextEngine (Python plugin)
└─ ContextHubClient (SDK)
└─ ContextHub Server (:8000)
└─ PostgreSQL + pgvector
| Requirement | Version | Install |
|---|---|---|
| macOS with Homebrew | — | https://brew.sh |
| Python | 3.11+ | brew install python@3.12 |
| Node.js | ≥ 22.12 | brew install node |
| pnpm | 9+ | npm install -g pnpm |
| PostgreSQL | 16 | brew install postgresql@16 |
| pgvector | — | brew install pgvector |
You also need an LLM API key (Anthropic or OpenAI) for the OpenClaw agent.
brew install postgresql@16
brew install pgvector
brew services start postgresql@16Verify:
pg_isready
# Expected: "accepting connections"psql postgres -c "CREATE USER contexthub WITH PASSWORD 'contexthub' SUPERUSER;"
psql postgres -c "CREATE DATABASE contexthub OWNER contexthub;"
psql postgresql://contexthub:contexthub@localhost:5432/contexthub -c "
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pgcrypto;
"cd /path/to/ContextHub
# Deactivate conda if active
conda deactivate
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pip install greenlet
pip install -e sdk/
pip install -e plugins/openclaw/cd /path/to/ContextHub
source .venv/bin/activate
alembic upgrade headcd /path/to/ContextHub/bridge
npm install
npm run buildgit clone https://github.com/openclaw/openclaw.git /path/to/public/openclaw
cd /path/to/public/openclaw
# If git SSH fails for some dependencies:
git config url."https://github.com/".insteadOf "git@github.com:"
pnpm install
pnpm ui:build
pnpm buildNote:
/path/to/public/openclawis the OpenClaw main repo (a Node.js project withpackage.json). Do not confuse it withContextHub/plugins/openclaw/, which is a Python plugin package.Note:
pnpm ui:buildis required for OpenClaw ≥ v2026.4.x. If you are on an older version (e.g. v2026.3.14), you can skip it —pnpm install && pnpm buildis sufficient.
cd /path/to/public/openclaw
pnpm openclaw plugins install -l /path/to/ContextHub/bridgeExpected output (warnings are OK):
Exclusive slot "contextEngine" switched from "legacy" to "contexthub".
Linked plugin path: ~/path/to/ContextHub/bridge
Restart the gateway to load plugins.
cd /path/to/public/openclaw
pnpm openclaw configureFollow the interactive prompts to set your LLM API key (Anthropic / OpenAI).
Or edit ~/.openclaw/openclaw.json directly:
{
"plugins": {
"slots": {
"contextEngine": "contexthub"
},
"entries": {
"contexthub": {
"enabled": true,
"config": {
"sidecarUrl": "http://localhost:9100"
}
}
}
}
}After the one-time setup, here is how to start everything each time.
PostgreSQL runs as a Homebrew service. It starts automatically on boot if
you ran brew services start postgresql@16. Verify it's running:
pg_isready
# Expected: "accepting connections"If not running:
brew services start postgresql@16cd /path/to/ContextHub
source .venv/bin/activate
uvicorn contexthub.main:app --port 8000Keep this terminal open. Verify in another tab:
curl http://localhost:8000/health
# Expected: {"status":"ok"}Note: If
OPENAI_API_KEYis not set in.env, the server uses a NoOp embedding client. Vector search returns limited results. This is expected for local MVP verification.
cd /path/to/ContextHub
source .venv/bin/activate
python bridge/src/sidecar.py \
--port 9100 \
--contexthub-url http://localhost:8000 \
--agent-id query-agent \
--account-id acmeKeep this terminal open. Verify:
curl http://localhost:9100/health
# Expected: {"status":"ok"}
curl http://localhost:9100/tools
# Expected: JSON array of 7 tool definitionscd /path/to/public/openclaw
pnpm openclaw gatewayKeep this terminal open. You should see the gateway start on port 18789. Look for the ContextHub plugin loading in the logs.
cd /path/to/public/openclaw
pnpm openclaw tuiYou can now chat with the agent. Behind the scenes:
- Every prompt:
assemble()auto-recalls relevant context from ContextHub and injects it into the system prompt. - Every response:
afterTurn()extracts reusable facts from the assistant's reply and writes them as private memories in ContextHub. - Agent tools: The agent can call
ls,read,grep,stat,contexthub_store,contexthub_promote, andcontexthub_skill_publish.
cd /path/to/public/openclaw
pnpm openclaw doctorLook for contexthub in the context engine section.
# Info
curl http://localhost:9100/info
# Simulate assemble (auto-recall)
curl -X POST http://localhost:9100/assemble \
-H "Content-Type: application/json" \
-d '{"sessionId": "test", "messages": [{"role": "user", "content": "What is the orders table schema?"}]}'
# Simulate tool dispatch
curl -X POST http://localhost:9100/dispatch \
-H "Content-Type: application/json" \
-d '{"name": "ls", "args": {"path": "ctx://"}}'This verifies the ContextHub server itself — multi-agent memory, skills, propagation:
cd /path/to/ContextHub
source .venv/bin/activate
python scripts/demo_e2e.pyThe sidecar supports per-request agent identity via X-Agent-Id header.
Different OpenClaw sessions can act as different ContextHub agents.
Alternatively, run multiple sidecars:
# Terminal 3a
python bridge/src/sidecar.py --port 9100 --agent-id query-agent
# Terminal 3b
python bridge/src/sidecar.py --port 9101 --agent-id analysis-agent# Option A: Truncate business data only
psql postgresql://contexthub:contexthub@localhost:5432/contexthub -c "
SET app.account_id = 'acme';
TRUNCATE contexts, dependencies, change_events,
table_metadata, lineage, table_relationships,
query_templates, skill_versions, skill_subscriptions
CASCADE;
"
# Option B: Full database reset
psql postgres -c "DROP DATABASE IF EXISTS contexthub;"
psql postgres -c "CREATE DATABASE contexthub OWNER contexthub;"
psql postgresql://contexthub:contexthub@localhost:5432/contexthub -c "
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pgcrypto;
"
alembic upgrade headcd /path/to/public/openclaw
pnpm openclaw plugins disable contexthub # disable
pnpm openclaw plugins enable contexthub # re-enableTo switch back to the built-in legacy context engine:
# Edit ~/.openclaw/openclaw.json
# Change plugins.slots.contextEngine to "legacy" (or remove the key)| Service | How to stop |
|---|---|
| OpenClaw TUI | Ctrl+C in Terminal 5 |
| OpenClaw Gateway | Ctrl+C in Terminal 4 |
| Python Sidecar | Ctrl+C in Terminal 3 |
| ContextHub Server | Ctrl+C in Terminal 2 |
| PostgreSQL | brew services stop postgresql@16 |
cd /path/to/public/openclaw
git config url."https://github.com/".insteadOf "git@github.com:"
pnpm installThe bridge package.json must include:
"openclaw": {
"extensions": ["./dist/index.js"]
}Ensure the bridge package.json has "name": "contexthub" (matching the
openclaw.plugin.json id).
psql postgres -c "ALTER USER contexthub WITH SUPERUSER;"Ensure the server is running on :8000 before starting the sidecar.
Check curl http://localhost:8000/health.
Clear leftover events:
psql postgresql://contexthub:contexthub@localhost:5432/contexthub -c "
UPDATE change_events
SET delivery_status = 'processed', processed_at = NOW()
WHERE delivery_status IN ('pending', 'retry', 'processing');
"Or disable the propagation engine in .env:
PROPAGATION_ENABLED=false
Check that Node.js ≥ 22.12 is installed:
node --versionCheck that the build succeeded:
cd /path/to/public/openclaw
ls dist/index.jsContextHub/
├── src/contexthub/ # FastAPI server (contexts, memories, skills, search, propagation)
├── sdk/ # Python SDK (ContextHubClient)
├── plugins/openclaw/ # Python ContextEngine plugin (assemble, afterTurn, tools)
├── bridge/
│ ├── openclaw.plugin.json # OpenClaw plugin manifest (kind: "context-engine")
│ ├── src/
│ │ ├── index.ts # Plugin entry: register(api) → registerContextEngine + registerTool
│ │ ├── bridge.ts # ContextHubBridge: TS ContextEngine impl → HTTP → sidecar
│ │ ├── tools.ts # 7 MVP tool definitions (ls/read/grep/stat/store/promote/publish)
│ │ └── sidecar.py # Python HTTP wrapper for the plugin (multi-agent via X-Agent-Id)
│ └── dist/ # Compiled JS (after npm run build)
├── scripts/demo_e2e.py # Standalone E2E demo (no OpenClaw needed)
├── tests/ # pytest suite
├── alembic/ # Database migrations
└── docker-compose.yml # PostgreSQL container (optional, Homebrew alternative above)