Prerequisites
Install these before running the installer. Quick check:
node --version && npm --version && zstd --version && node --input-type=module -e "import 'lbug'" && echo "✅ all good"
| Dependency | Version | macOS | Ubuntu / Debian | Fedora |
|---|---|---|---|---|
| Node.js | 18+ | brew install node@22 | NodeSource (see below) | sudo dnf install -y nodejs npm |
| lbug | 0.14.3+ | npm install -g lbug | ||
| zstd | 1.5+ | brew install zstd | sudo apt-get install -y zstd | sudo dnf install -y zstd |
| curl | any | pre-installed | sudo apt-get install -y curl | pre-installed |
| OpenClaw | latest | github.com/openclaw/openclaw | ||
macOS — step by step
# 1. Install Homebrew (skip if already installed) /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" # 2. Install Node.js 22 LTS (includes npm) brew install node@22 echo 'export PATH="/opt/homebrew/opt/node@22/bin:$PATH"' >> ~/.zshrc source ~/.zshrc # 3. Install lbug globally npm install -g lbug # 4. Install zstd brew install zstd # curl is pre-installed on macOS — no action needed
Ubuntu / Debian — step by step
# 1. Install curl sudo apt-get update && sudo apt-get install -y curl # 2. Add NodeSource repo and install Node.js 22 LTS (includes npm) # (apt's default nodejs is often too old — NodeSource guarantees v22) curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt-get install -y nodejs # 3. Install lbug globally npm install -g lbug # 4. Install zstd sudo apt-get install -y zstd
Fedora — step by step
# 1. Install Node.js 22 and npm sudo dnf install -y nodejs npm # 2. Install lbug globally npm install -g lbug # 3. Install zstd sudo dnf install -y zstd # curl is pre-installed on Fedora — no action needed
Installation
One-command install
# Lite — skills + embeddings (~300 MB compressed) curl -fsSL https://raw.githubusercontent.com/alphaonedev/openclaw-graph/main/install.sh | bash -s -- --lite # Full — skills + 545k DevDocs reference nodes (~500 MB compressed) curl -fsSL https://raw.githubusercontent.com/alphaonedev/openclaw-graph/main/install.sh | bash -s -- --full # From a cloned repo bash install.sh --lite # skills only bash install.sh --full # skills + DevDocs bash install.sh --version v1.3 # pin a specific release bash install.sh --verify # check an existing DB
Manual install
git clone https://github.com/alphaonedev/openclaw-graph.git cd openclaw-graph npm install # Download and decompress the DB curl -L https://github.com/alphaonedev/openclaw-graph/releases/download/v1.3/alphaone-skills-full.db.zst \ | zstd -d > ladybugdb/db/alphaone-skills.db # Verify node ladybugdb/scripts/query.js --stats
What the DB contains (v1.3)
| Table | Nodes | Description |
|---|---|---|
| Skill | 316 | Skills across 27 clusters |
| Reference | 545,072 | DevDocs entries (718 docsets) — full tier only |
| Soul | 4 | Prime Directive, Identity, Safety, Heartbeat Protocol |
| Memory | 2 | Principal (placeholder), Infrastructure (placeholder) |
| AgentConfig | 9 | Every Session, Delegation, Safety, Heartbeats, Memory, TOON, Search Resilience, Schema Rules, Path Aliases |
| Tool | 26 | All standard OpenClaw tools |
| QueryMetrics | grows | Auto-recorded by query.js on every GRAPH directive resolution — view with sync-metrics.mjs |
Table sizes: Workspace tables (Soul, Memory, AgentConfig) hold 4–30 nodes each. Full table scans are sub-millisecond at this scale. lbug 0.14.x does not expose a secondary-index DDL for regular node properties; indexes will be added here when lbug support lands.
Import Your Workspace
Already running OpenClaw with flat markdown files? One command loads them into LadybugDB.
Quick start
# From your openclaw-graph directory — reads ~/.openclaw/workspace/ by default node ladybugdb/scripts/import-workspace.mjs # Preview what will be imported without writing anything node ladybugdb/scripts/import-workspace.mjs --dry-run # Import + replace flat files with GRAPH stubs (originals backed up to *.bak) node ladybugdb/scripts/import-workspace.mjs --write-stubs # Custom path or workspace name node ladybugdb/scripts/import-workspace.mjs --workspace-dir ~/my/path --workspace-name myagent # Replace existing nodes node ladybugdb/scripts/import-workspace.mjs --overwrite
File → Node mapping
| File | Node type | Section → field | Notes |
|---|---|---|---|
SOUL.md | Soul | ## heading → section | Ordered by priority (file order) |
MEMORY.md | Memory | ## heading → domain | Timestamped on import date |
USER.md | Memory | ## heading → User: <heading> | Queryable separately via STARTS WITH 'User:' |
TOOLS.md | Tool | ## heading → name | No workspace column — tools are global |
AGENTS.md | AgentConfig | ## heading → key | Drives AGENTS.md stub query |
Format requirement: Each file is parsed by ## headings — each heading becomes one graph node. Files with no ## headings are imported as a single node titled Main. Files that already contain a GRAPH stub directive are automatically skipped.
What --write-stubs does
# Before: flat file (~1,800 bytes) ~/.openclaw/workspace/SOUL.md # After --write-stubs: ~/.openclaw/workspace/SOUL.md # ← single-line GRAPH stub (144 bytes) ~/.openclaw/workspace/SOUL.md.bak # ← original backed up automatically
OpenClaw resolves the stub at runtime from LadybugDB — your content is preserved in the graph, not the file.
Database Layout
ladybugdb/ ├── db/ │ └── alphaone-skills.db # Single-file embedded DB (no daemon) ├── schema/ │ ├── nodes.cypher # Skill + Reference DDL │ ├── edges.cypher # Relationship DDL │ └── workspace-nodes.cypher # Soul, Memory, AgentConfig, Tool DDL └── scripts/ ├── query.js # CLI query tool (auto-records QueryMetrics) ├── loader.js # Load SKILL.md files into DB ├── seed-default-workspace.mjs # Seed default workspace nodes ├── import-workspace.mjs # Load flat SOUL/MEMORY/USER/TOOLS/AGENTS.md into DB ├── sync-metrics.mjs # View / reset QueryMetrics dashboard └── seed-workspace.js # Custom workspace seeder
LadybugDB is an embedded graph database (KuzuDB). The entire DB is a single file — no daemon, no port, no configuration. Queries execute in-process via the lbug Node.js bindings.
CLI Reference
All commands use node ladybugdb/scripts/query.js:
Skill queries
# Text search — matches against name, description, embedding hints node ladybugdb/scripts/query.js "build a SwiftUI watchOS app" # Cluster filter — list all skills in a cluster node ladybugdb/scripts/query.js --cluster devops-sre node ladybugdb/scripts/query.js --cluster financial # Skill graph traversal — show a skill and its relationships node ladybugdb/scripts/query.js --skill cloudflare --hops 2 # Stats — total skills, clusters, auth-required flags node ladybugdb/scripts/query.js --stats
Raw Cypher queries
# Standard mode — labeled output for debugging node ladybugdb/scripts/query.js --cypher "MATCH (s:Skill) RETURN count(s) AS total" # Workspace mode — clean markdown output (used by workspace.ts) node ladybugdb/scripts/query.js --workspace --cypher \ "MATCH (a:AgentConfig {workspace:'openclaw'}) RETURN a.key, a.value ORDER BY a.id"
Workspace node queries
# List all Soul nodes node ladybugdb/scripts/query.js --cypher \ "MATCH (s:Soul {workspace:'openclaw'}) RETURN s.section, s.priority ORDER BY s.priority" # List all AgentConfig nodes node ladybugdb/scripts/query.js --cypher \ "MATCH (a:AgentConfig {workspace:'openclaw'}) RETURN a.key ORDER BY a.id" # List available tools node ladybugdb/scripts/query.js --cypher \ "MATCH (t:Tool) WHERE t.available = true RETURN t.name, t.notes ORDER BY t.name" # Query DevDocs references node ladybugdb/scripts/query.js --cypher \ "MATCH (r:Reference) WHERE r.source = 'python~3.12' AND r.path STARTS WITH 'library/' RETURN r.title, r.path LIMIT 20"
Output formats
The --workspace flag activates clean markdown output (no labels), which is what workspace.ts uses when resolving GRAPH directives. Without it, output is labeled for human reading.
| Data shape | Format |
|---|---|
section + content | Soul markdown (## Section\n\nContent) |
domain + content | Memory markdown (## Domain\n\nContent) |
key + value | AgentConfig markdown (- **Key**: Value) |
name + notes | Tool list (- **Name**: Notes) |
| Other | JSON (debug/dev use) |
Workspace Setup
1. Apply the workspace.ts patch
The patch modifies OpenClaw's workspace.ts to resolve GRAPH directives:
cd /path/to/openclaw git apply path/to/openclaw-graph/patches/workspace-cache-fix.patch pnpm build
What the patch does:
- Intercepts
readFileWithCache()to detect<!-- GRAPH: ... -->directives - Executes Cypher queries via
execFileAsync(non-blocking) - Caches results with adaptive TTL:
60s × log₁₀(hit_count + 10) - In-flight deduplication prevents thundering herd on cache expiry
2. Deploy workspace stubs
cp workspace-stubs/*.md ~/.openclaw/workspace/
Each stub is a single-line file like:
<!-- GRAPH: MATCH (s:Soul) WHERE s.workspace = 'openclaw' RETURN s.section AS section, s.content AS content ORDER BY s.priority ASC -->
3. Verify resolution
# Test that the directive resolves correctly node ladybugdb/scripts/query.js --workspace --cypher \ "MATCH (s:Soul {workspace:'openclaw'}) RETURN s.section, s.content ORDER BY s.priority" # Expected: formatted markdown with Prime Directive, Identity, Safety, Heartbeat Protocol
4. Customize your workspace
See the User Guide → Customizing for step-by-step personalization.
Cron Job Integration
openclaw-graph supports scheduled tasks (cron jobs) that query the graph database. Cron jobs typically run as lightweight OpenClaw sessions that:
- Load workspace context via GRAPH directives (same as interactive sessions)
- Execute domain-specific prompts (intel, monitoring, alerts)
- Write output to files or send notifications
Cron architecture
Cron Scheduler (crontab / launchd / systemd) └── Every N minutes: run openclaw session │ ▼ OpenClaw Session (cron mode) ├── Load AGENTS.md → GRAPH: AgentConfig ├── Load TOOLS.md → GRAPH: Tool ├── Execute prompt (task-specific) └── Write output / send alerts │ --workspace --cypher ▼ LadybugDB (alphaone-skills.db) ├── AgentConfig → session behavior ├── Skill → task-relevant skills └── Reference → documentation context
Cron session bootstrap
Cron/sub-agent sessions use a minimal bootstrap. OpenClaw's MINIMAL_BOOTSTRAP_ALLOWLIST loads only:
- AGENTS.md (AgentConfig nodes — session behavior, delegation rules)
- TOOLS.md (available tools and usage notes)
SOUL.md and MEMORY.md are skipped for cron sessions to reduce prompt size.
AgentConfig nodes relevant to cron
| Node | Purpose |
|---|---|
agentcfg-*-every-session | Bootstrap instructions (read SOUL, USER, memory) |
agentcfg-*-delegation | Sub-agent spawning rules |
agentcfg-*-search-resilience | Retry/fallback when web_search fails |
agentcfg-*-schema-rules | Output validation requirements |
agentcfg-*-path-aliases | Compact path notation ($PY, $DB, etc.) |
agentcfg-*-toon | JSON compression for large payloads |
Example: cron job definition
{
"name": "daily-report",
"schedule": "0 8 * * *",
"workspace": "openclaw",
"prompt": "Generate today's daily report. Query relevant skills with: node ladybugdb/scripts/query.js --cluster financial",
"output": "~/.openclaw/workspace/reports/daily-$(date +%Y-%m-%d).md"
}Querying skills from cron prompts
# Find relevant skills for a domain node ladybugdb/scripts/query.js "kubernetes monitoring alerts" # Get specific skill content node ladybugdb/scripts/query.js --skill kubernetes-ops --hops 1 # Query reference docs node ladybugdb/scripts/query.js --cypher \ "MATCH (r:Reference {source:'kubernetes'}) WHERE r.path STARTS WITH 'api/' RETURN r.title, r.content LIMIT 5"
Fleet Management
For multi-instance deployments, each OpenClaw instance gets its own workspace ID. All instances share the same DB file (no lock contention — LadybugDB is read-heavy).
Seed separate workspaces
node ladybugdb/scripts/seed-default-workspace.mjs --workspace intel-agent node ladybugdb/scripts/seed-default-workspace.mjs --workspace code-agent node ladybugdb/scripts/seed-default-workspace.mjs --workspace ops-agent
Point stubs to the correct workspace
# Instance A stubs (~/.openclaw/workspace-intel/) # SOUL.md: # <!-- GRAPH: MATCH (s:Soul) WHERE s.workspace = 'intel-agent' RETURN s.section AS section, s.content AS content ORDER BY s.priority ASC -->
Fleet topology example
| Port | Instance | Workspace ID |
|---|---|---|
| 18790 | A — Intel/OSINT | intel-agent |
| 18791 | B — Compute | compute-agent |
| 18792 | C — Browser | browser-agent |
| 18793 | D — Code/GitHub | code-agent |
| 18794 | E — Infra | infra-agent |
| 18795 | F — Memory/Graph | graph-agent |
| 18796 | G — General | general-agent |
| 18797 | H — Standby | standby-agent |
Each instance runs its own DB copy (install.sh --full). No shared DB, no lock contention.
Per-workspace tool overrides
# Disable delegation for the browser-only instance node ladybugdb/scripts/query.js --cypher \ "MATCH (t:Tool {id:'tool-sessions-spawn'}) \ WHERE EXISTS { MATCH (a:AgentConfig {workspace:'browser-agent'}) } \ SET t.available = false"
Service Management
Architecture note: openclaw-graph has no daemon of its own. It is embedded directly inside the OpenClaw gateway process. "Restarting the graph" means restarting the OpenClaw gateway. The LadybugDB file is always accessible directly via query.js --stats regardless of gateway state.
macOS (launchd)
OpenClaw installs a launchd service with label ai.openclaw.gateway.
# Start launchctl bootstrap gui/$UID \ ~/Library/LaunchAgents/ai.openclaw.gateway.plist # Stop launchctl bootout gui/$UID/ai.openclaw.gateway # Restart (stop + start in one command) launchctl kickstart -k gui/$UID/ai.openclaw.gateway # Status — look for "state = running" and "pid =" launchctl print gui/$UID/ai.openclaw.gateway | grep -E "state|pid"
macOS log files
# Structured log (stdout) — primary log tail -f ~/.openclaw/logs/gateway.log # Error log (stderr) tail -f ~/.openclaw/logs/gateway.err.log # macOS unified log stream (real-time, subsystem ai.openclaw) log stream --predicate 'subsystem == "ai.openclaw"' --level info # Or use the bundled clawlog utility from the openclaw directory bash scripts/clawlog.sh
Ubuntu (systemd)
OpenClaw installs a user-scope systemd unit: openclaw-gateway.service.
# Start systemctl --user start openclaw-gateway.service # Stop systemctl --user stop openclaw-gateway.service # Restart systemctl --user restart openclaw-gateway.service # Status systemctl --user status openclaw-gateway.service
Ubuntu log files
# Live log stream via journald journalctl --user -u openclaw-gateway.service -f # Or read the flat log files directly tail -f ~/.openclaw/logs/gateway.log tail -f ~/.openclaw/logs/gateway.err.log
Fedora (systemd)
Same commands as Ubuntu — both use user-scope systemd.
# Start systemctl --user start openclaw-gateway.service # Stop systemctl --user stop openclaw-gateway.service # Restart systemctl --user restart openclaw-gateway.service # Status systemctl --user status openclaw-gateway.service
Fedora log files
# Live log stream via journald journalctl --user -u openclaw-gateway.service -f # Or read the flat log files directly tail -f ~/.openclaw/logs/gateway.log tail -f ~/.openclaw/logs/gateway.err.log
DB health check (all platforms)
These run directly against the LadybugDB file — no gateway required.
# Full stats: node count, edge count, DB file size node ~/openclaw-graph/ladybugdb/scripts/query.js --stats # Quick workspace sanity check node ~/openclaw-graph/ladybugdb/scripts/query.js --cypher \ "MATCH (s:Soul {workspace:'openclaw'}) RETURN count(s) AS souls" # Check all workspace node counts node ~/openclaw-graph/ladybugdb/scripts/query.js --cypher \ "MATCH (n) WHERE n.workspace = 'openclaw' RETURN labels(n)[0] AS type, count(n) AS n ORDER BY type"
Log file locations (all platforms)
| File | Contains |
|---|---|
~/.openclaw/logs/gateway.log | Gateway stdout — normal operational output |
~/.openclaw/logs/gateway.err.log | Gateway stderr — errors and warnings |
Query Metrics
query.js automatically records a row into QueryMetrics every time a GRAPH directive resolves from a workspace stub (--workspace mode). No configuration needed — it just works after install.
New install? QueryMetrics starts empty and fills itself automatically. The first entry appears after OpenClaw loads any workspace stub for the first time.
View the dashboard
# Dashboard — top 20 queries by hit count node ladybugdb/scripts/sync-metrics.mjs # Show top 40 node ladybugdb/scripts/sync-metrics.mjs --top 40 # Include queries that returned 0 results node ladybugdb/scripts/sync-metrics.mjs --zero # Raw JSON (for scripting or export) node ladybugdb/scripts/sync-metrics.mjs --json # Clear all metrics (e.g. after a workspace reset) node ladybugdb/scripts/sync-metrics.mjs --reset
What the dashboard shows
| Column | Meaning |
|---|---|
hits | Times this Cypher query returned ≥1 row |
miss | Times this Cypher query returned 0 rows |
rate | Hit rate percentage (hits / total) |
avg | Rolling mean execution time (hits only, Welford algorithm) |
p95 | High-water mark — rises instantly on slow queries, decays slowly |
last_hit | UTC timestamp of most recent successful hit |
Upgrading
When you upgrade to a new release, the DB is replaced. Workspace nodes live in the DB.
Upgrade workflow
# 1. Backup current workspace nodes node ladybugdb/scripts/query.js --cypher \ "MATCH (s:Soul {workspace:'myworkspace'}) RETURN s.id, s.section, s.content, s.priority" \ > workspace-backup.json # 2. Run install.sh (downloads new DB, overwrites old) bash install.sh --full # 3. Re-seed your workspace node ladybugdb/scripts/seed-default-workspace.mjs --workspace myworkspace # or: node ladybugdb/scripts/seed-myagent.mjs # 4. Verify node ladybugdb/scripts/query.js --cypher \ "MATCH (a:AgentConfig {workspace:'myworkspace'}) RETURN count(a) AS n"
Recommended: Keep your workspace customizations in a seed script (forked from seed-default-workspace.mjs). After any DB upgrade, re-run the script. This is more reliable than manual backup/restore.
Backup & Restore
Full DB backup
# The DB is a single file — just copy it
cp ladybugdb/db/alphaone-skills.db ladybugdb/db/alphaone-skills.db.bakExport workspace nodes to JSON
# Export each table for table in Soul Memory AgentConfig Tool; do node ladybugdb/scripts/query.js --cypher \ "MATCH (n:${table}) RETURN n.*" > backup-${table}.json done
Environment Variables
| Variable | Default | Description |
|---|---|---|
OPENCLAW_GRAPH_NODE_BIN | node | Path to Node.js binary for query.js |
OPENCLAW_GRAPH_QUERY_SCRIPT | ~/openclaw-graph/ladybugdb/scripts/query.js | Path to CLI query script |
NODE_BIN | node | Used by install.sh |
RELEASE_VERSION | latest | Pin install.sh to a specific release |
Troubleshooting
GRAPH directive returns empty
Symptom: Workspace file loads but content is empty.
Check:
# 1. Is the DB present? ls -lh ladybugdb/db/alphaone-skills.db # 2. Can query.js connect? node ladybugdb/scripts/query.js --stats # 3. Does the workspace have nodes? node ladybugdb/scripts/query.js --cypher \ "MATCH (a:AgentConfig {workspace:'openclaw'}) RETURN count(a) AS n" # 4. Is the directive syntax correct? # Must be: <!-- GRAPH: <cypher> --> # Must be the FIRST LINE of the file # Cypher must be a single line
"Table X does not exist"
Cause: The workspace tables haven't been created. This happens if you installed a pre-v1.3 DB.
Fix:
node ladybugdb/scripts/seed-default-workspace.mjs
Stale workspace content
Cause: Graph query cache hasn't expired (60s TTL).
Fix: Wait 60 seconds, or restart the OpenClaw process. The cache is in-memory only.
CLI subprocess slow (~100ms+)
This is expected. The ~100ms cost is Node.js process startup + lbug init — not the query itself (which takes <1ms). The cache ensures this cost is paid at most once per 60 seconds per unique query.
DB file locked / corrupted
# Check for WAL files ls ladybugdb/db/alphaone-skills.db* # If .wal files exist, the DB may have been interrupted during a write # Backup and re-install mv ladybugdb/db/alphaone-skills.db ladybugdb/db/alphaone-skills.db.corrupted bash install.sh --full node ladybugdb/scripts/seed-default-workspace.mjs
Performance Reference
| Query | In-process | CLI subprocess |
|---|---|---|
| Skill PK lookup | 0.18ms | ~111ms |
| AgentConfig (9 nodes) | 0.33ms | ~127ms |
| Tool query (26 nodes) | 0.41ms | ~106ms |
| Reference PK (545k table) | 0.11ms | — |
| Full skill scan (316) | 2.02ms | — |
All in-process queries are sub-millisecond. CLI subprocess cost (~104ms) is amortized by the 60–180s adaptive TTL cache. All 5 workspace GRAPH directives resolve in parallel via Promise.allSettled() — cold workspace load is ~104ms total, not 5×104ms.
Workspace tables (Soul, Memory, AgentConfig) hold 4–30 nodes each — full table scans are sub-millisecond at this scale. lbug 0.14.x does not expose a secondary-index DDL for non-PK properties; the scan cost is negligible today and indexes will be added when lbug support lands.
Full benchmark data: benchmarks/results.md