User Guide

How workspace stubs work, what each node type does, and how to personalize your agent.

Overview

openclaw-graph replaces OpenClaw's flat workspace files (SOUL.md, MEMORY.md, TOOLS.md, AGENTS.md) with single-line stubs that resolve against an embedded graph database at session start.

Before (flat files)After (graph stubs)Node type
SOUL.md~1,800 bytes of markdown144 bytes — one GRAPH directiveSoul
MEMORY.md~5,000+ bytes130 bytesMemory
USER.md~800+ bytes142 bytesMemory (prefix: User:)
TOOLS.md~2,000 bytes112 bytesTool
AGENTS.md~500 bytes127 bytesAgentConfig
Total~11,000+ bytes~655 bytes

Content is stored as nodes in LadybugDB (an embedded graph database). Stubs query the database at runtime and inject the resolved content into your agent's system prompt — exactly as if you'd written it by hand.

How It Works

OpenClaw Session Start

  1. Read ~/.openclaw/workspace/SOUL.md
  2. Detect <!-- GRAPH: ... --> directive on first line
  3. Execute Cypher query against LadybugDB
  4. Format result as markdown
  5. Inject into system prompt (as if SOUL.md was flat)

  Same for MEMORY.md, AGENTS.md, TOOLS.md

From the agent's perspective, nothing changes — it sees the same markdown it always did. The difference is that the content now lives in a queryable graph database instead of hand-maintained files.

Workspace Files

After deploying stubs, your workspace directory looks like this:

~/.openclaw/workspace/
├── SOUL.md      → resolves Soul nodes (identity, prime directive, safety)
├── MEMORY.md    → resolves Memory nodes (project facts, infrastructure)
├── USER.md      → resolves Memory nodes where domain starts with 'User:'
├── AGENTS.md    → resolves AgentConfig nodes (session behavior, delegation)
└── TOOLS.md     → resolves Tool nodes (available tools and usage notes)

Each file is a single line:

SOUL.md

<!-- GRAPH: MATCH (s:Soul) WHERE s.workspace = 'openclaw' RETURN s.section AS section, s.content AS content ORDER BY s.priority ASC LIMIT 8 -->

MEMORY.md

<!-- GRAPH: MATCH (m:Memory) WHERE m.workspace = 'openclaw' RETURN m.domain AS domain, m.content AS content ORDER BY m.domain -->

USER.md

User context lives as Memory nodes with a User: domain prefix — importable from your existing USER.md via import-workspace.mjs.

<!-- GRAPH: MATCH (m:Memory) WHERE m.workspace = 'openclaw' AND m.domain STARTS WITH 'User:' RETURN m.domain AS domain, m.content AS content ORDER BY m.domain -->

AGENTS.md

<!-- GRAPH: MATCH (a:AgentConfig) WHERE a.workspace = 'openclaw' RETURN a.key AS section, a.value AS content ORDER BY a.id -->

TOOLS.md

<!-- GRAPH: MATCH (t:Tool) WHERE t.available = true RETURN t.name AS name, t.notes AS notes ORDER BY t.name -->

Node Types — Soul SOUL

Purpose: Defines your agent's identity, core directives, and behavioral boundaries.

Schema

FieldTypeDescription
idSTRINGUnique identifier (e.g., soul-openclaw-identity)
workspaceSTRINGWorkspace this node belongs to (default: openclaw)
sectionSTRINGSection heading (e.g., "Prime Directive", "Identity")
contentSTRINGMarkdown content for this section
priorityINT64Sort order — lower numbers load first (default: 5)
protectedBOOLEANIf true, cannot be overwritten by --reset (default: false)

Default nodes (4)

PrioritySectionPurpose
1Prime DirectiveCore mission statement — what the agent exists to do
2IdentityAgent name, role, emoji, workspace ID
3SafetyBehavioral guardrails and constraints
4Heartbeat ProtocolPeriodic self-check and health reporting format

Resolved output format: ## Section\n\nContent (standard markdown headings)

Memory MEMORY

Purpose: Stores factual knowledge the agent needs across sessions — who it works for, what infrastructure exists, API keys (as env var references), project state.

Schema

FieldTypeDescription
idSTRINGUnique identifier (e.g., mem-openclaw-principal)
workspaceSTRINGWorkspace this node belongs to (default: openclaw)
domainSTRINGCategory label (e.g., "Principal", "Infrastructure")
contentSTRINGFactual content for this domain
timestampSTRINGWhen this memory was last updated (ISO format)

Default nodes (2)

DomainPurpose
PrincipalWho the agent serves — name, timezone, preferred contact channel
InfrastructureEnvironment facts — DB paths, Node.js location, workspace directory

Both ship as placeholders — you fill in your own details. See Customizing below.

Resolved output format: ## Domain\n\nContent

AgentConfig CONFIG

Purpose: Controls agent session behavior — how it delegates tasks, handles errors, compresses output, validates schemas, and resolves paths.

Schema

FieldTypeDescription
idSTRINGUnique identifier (e.g., agentcfg-openclaw-delegation)
workspaceSTRINGWorkspace this node belongs to (default: openclaw)
keySTRINGConfiguration key (displayed as section heading)
valueSTRINGConfiguration value (displayed as content)

Default nodes (9)

KeyPurpose
Every SessionBootstrap instructions — what to read on every session start
DelegationRules for spawning sub-agents (when to delegate, how many)
SafetySession-level safety behaviors (confirmation thresholds, etc.)
HeartbeatsPeriodic health check format and interval
MemoryHow to persist and retrieve memories across sessions
Token Optimization — TOONJSON compression rules for large payloads (30-60% token savings)
Search ResilienceRetry and fallback strategies when web_search fails
Schema RulesOutput validation requirements for structured data
Path AliasesCompact path notation ($PY, $DB, $WS, etc.) for prompt efficiency

Resolved output format: - **Key**: Value (markdown list items)

Session loading: In cron/sub-agent sessions, OpenClaw's MINIMAL_BOOTSTRAP_ALLOWLIST loads only AGENTS.md + TOOLS.md. SOUL.md and MEMORY.md are skipped to reduce prompt size.

Tool TOOL

Purpose: Declares which tools the agent can use, with usage notes.

Schema

FieldTypeDescription
idSTRINGUnique identifier (e.g., tool-web-search)
nameSTRINGTool name as the agent sees it
availableBOOLEANWhether the tool is currently enabled (default: true)
notesSTRINGUsage notes, restrictions, or tips

Default nodes: 21 tools covering all standard OpenClaw capabilities.

Set available = false to disable a tool for a specific agent (e.g., disable sessions_spawn for a standalone agent that shouldn't delegate).

Resolved output format: - **Name**: Notes (markdown list items)

Skill

Purpose: The skill graph — 316 skills across 27 clusters representing capabilities an agent can be asked to perform.

Schema

FieldTypeDescription
idSTRINGUnique identifier (e.g., skill-kubernetes-ops)
nameSTRINGHuman-readable skill name
clusterSTRINGSkill cluster (e.g., devops-sre, financial, python)
descriptionSTRINGWhat this skill does
tagsSTRING[]Searchable tags
authorization_requiredBOOLEANWhether this skill needs explicit user approval
scopeSTRINGScope category (default: general)
model_hintSTRINGSuggested model for this skill
embedding_hintSTRINGSemantic search hint text
skill_pathSTRINGPath to skill definition file (if installed)
clawhub_installSTRINGClawHub install command (if available)

Skills are queried via the CLI — they're not loaded into workspace stubs:

# Search by natural language
node ladybugdb/scripts/query.js "build a SwiftUI watchOS app"

# Filter by cluster
node ladybugdb/scripts/query.js --cluster devops-sre

# Traverse relationships
node ladybugdb/scripts/query.js --skill cloudflare --hops 2

Reference

Purpose: 545,072 entries from 718 DevDocs docsets — programming language documentation, framework APIs, library references. Available in the Full tier only.

References are queried on-demand, not loaded into workspace stubs:

# Find Python standard library docs
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"

GRAPH Directive Specification

Format & Rules

<!-- GRAPH: <cypher-query> -->
  1. Must be the first line of the workspace file
  2. Must be a single line — no multi-line Cypher
  3. Must start with <!-- GRAPH: and end with -->
  4. The Cypher query is extracted and executed via execFileAsync(node, [query.js, '--workspace', '--cypher', ...])

Return column conventions

The output format is determined by the column names returned by your Cypher query:

Return columnsOutput formatUsed by
section + content## Section\n\nContentSOUL.md
domain + content## Domain\n\nContentMEMORY.md
key + value- **Key**: ValueAGENTS.md
name + notes- **Name**: NotesTOOLS.md
Other columnsJSON (debug/dev use)Custom queries

Caching

Resolved results are cached with a three-layer strategy:

  1. Disk stub cacheworkspaceFileCache keyed by file mtime (if file hasn't changed, skip re-read)
  2. Graph query cachegraphQueryCache with adaptive TTL: 60s × log₁₀(hit_count + 10)
  3. In-flight deduplicationgraphQueryInFlight prevents thundering herd when multiple files resolve simultaneously

In practice, the Cypher query is executed at most once per 60 seconds per unique query. Subsequent reads return cached markdown instantly.

Workspace Loading Flow

Interactive sessions

Session Start
  ├── Load SOUL.md     → GRAPH directive → Soul nodes → system prompt
  ├── Load MEMORY.md   → GRAPH directive → Memory nodes → system prompt
  ├── Load AGENTS.md   → GRAPH directive → AgentConfig nodes → system prompt
  └── Load TOOLS.md    → GRAPH directive → Tool nodes → system prompt

All four files are loaded. The agent receives the full context.

Cron / sub-agent sessions

Session Start (minimal bootstrap)
  ├── Load AGENTS.md   → GRAPH directive → AgentConfig nodes → system prompt
  └── Load TOOLS.md    → GRAPH directive → Tool nodes → system prompt

Only AGENTS.md and TOOLS.md are loaded (MINIMAL_BOOTSTRAP_ALLOWLIST). This reduces prompt size for automated tasks that don't need identity or memory context.

Customizing Your Workspace

Option A — Edit nodes with Cypher

Best for quick changes to individual nodes.

# Update your agent's identity
node ladybugdb/scripts/query.js --cypher \
  "MATCH (s:Soul {id:'soul-openclaw-identity'}) \
   SET s.content = 'Name: Aria | Role: DevOps agent | Emoji: 🛡️'"

# Fill in the Principal memory (who you are)
node ladybugdb/scripts/query.js --cypher \
  "MATCH (m:Memory {id:'mem-openclaw-principal'}) \
   SET m.content = 'Name: Alice | Timezone: America/Chicago | Channel: signal'"

# Fill in Infrastructure memory
node ladybugdb/scripts/query.js --cypher \
  "MATCH (m:Memory {id:'mem-openclaw-infrastructure'}) \
   SET m.content = 'DB: ~/myapp/ladybugdb/db/alphaone-skills.db | Node: /usr/local/bin/node'"

# Add a new memory domain
node ladybugdb/scripts/query.js --cypher \
  "CREATE (m:Memory { \
     id: 'mem-openclaw-api-keys', \
     workspace: 'openclaw', \
     domain: 'API Keys', \
     content: 'Brave Search: \$BRAVE_API_KEY | xAI: \$XAI_API_KEY', \
     timestamp: '2026-01-01' \
   })"

Option B — Fork the seed script

Best for reproducible, version-controlled workspace definitions.

cp ladybugdb/scripts/seed-default-workspace.mjs ladybugdb/scripts/seed-myagent.mjs
# Edit SOUL, MEMORY, AGENT_CONFIG, TOOLS arrays
node ladybugdb/scripts/seed-myagent.mjs --workspace myagent --reset

Then update your stubs to point to your workspace:

# In each stub, change workspace = 'openclaw' to workspace = 'myagent'
sed -i '' "s/workspace = 'openclaw'/workspace = 'myagent'/g" ~/.openclaw/workspace/*.md

Option C — Multiple workspaces

For running several agents with different personalities or capabilities. See Fleet Management in the Admin Guide.

Keeping customizations across upgrades

When the DB is replaced during an upgrade, workspace nodes are lost. Two strategies:

  1. Re-run your seed script after every install.sh run (recommended)
  2. Export nodes before upgrading:
node ladybugdb/scripts/query.js --cypher \
  "MATCH (s:Soul {workspace:'openclaw'}) RETURN s.id, s.section, s.content, s.priority" \
  > workspace-backup.json

See Upgrading in the Admin Guide for the full workflow.

Default Node IDs

IDTypeSection / Domain / Key
soul-openclaw-prime-directiveSoulPrime Directive
soul-openclaw-identitySoulIdentity
soul-openclaw-safetySoulSafety
soul-openclaw-heartbeatSoulHeartbeat Protocol
mem-openclaw-principalMemoryPrincipal
mem-openclaw-infrastructureMemoryInfrastructure
agentcfg-openclaw-every-sessionConfigEvery Session
agentcfg-openclaw-delegationConfigDelegation
agentcfg-openclaw-safetyConfigSafety
agentcfg-openclaw-heartbeatsConfigHeartbeats
agentcfg-openclaw-memoryConfigMemory
agentcfg-openclaw-toonConfigToken Optimization — TOON
agentcfg-openclaw-search-resilienceConfigSearch Resilience
agentcfg-openclaw-schema-rulesConfigSchema Rules
agentcfg-openclaw-path-aliasesConfigPath Aliases

Plus 21 Tool nodes (tool-web-search, tool-sessions-spawn, etc.).

Import Your Existing Workspace

Already running OpenClaw with flat SOUL.md, MEMORY.md, USER.md, TOOLS.md, AGENTS.md files? One command loads them all into LadybugDB:

# From your openclaw-graph directory
node ladybugdb/scripts/import-workspace.mjs

The importer scans ~/.openclaw/workspace/ by default, parses each file by ## headings, and creates the correct graph nodes. Files already containing a <!-- GRAPH: --> stub are automatically skipped.

Options

# Preview what will be imported — no DB writes
node ladybugdb/scripts/import-workspace.mjs --dry-run

# Import + replace flat files with GRAPH stubs (backs up originals to *.bak)
node ladybugdb/scripts/import-workspace.mjs --write-stubs

# Replace existing nodes
node ladybugdb/scripts/import-workspace.mjs --overwrite

# Custom source directory or workspace name
node ladybugdb/scripts/import-workspace.mjs --workspace-dir ~/my/path --workspace-name myagent

File → Node mapping

FileNode typeHow sections map
SOUL.mdSoul## Headingsection field, body → content
MEMORY.mdMemory## Headingdomain field, body → content
USER.mdMemory## HeadingUser: <Heading> domain — queryable separately
TOOLS.mdTool## Headingname field, body → notes
AGENTS.mdAgentConfig## Headingkey field, body → value

Format tip: Structure your markdown files with ## headings — each heading becomes one graph node. Files with no ## headings are imported as a single node titled Main.

FAQ

Do I need to change my prompts or workflows?

No. The agent sees the same markdown content it always did. The graph database is transparent — it's a storage and delivery mechanism, not a new interface.

What happens if the database is missing?

The GRAPH directive returns empty content. Your agent will start with blank workspace sections. Run install.sh to download the database, then seed-default-workspace.mjs if workspace nodes are missing.

How do I import my existing flat workspace files?

Run node ladybugdb/scripts/import-workspace.mjs from your openclaw-graph directory. It reads ~/.openclaw/workspace/, parses each file by ## headings, and creates the correct graph nodes. Add --write-stubs to automatically replace your flat files with GRAPH stubs (originals backed up as *.bak). See the Import Your Files section above.

Can I mix flat files and graph stubs?

Yes. Any workspace file without a <!-- GRAPH: ... --> directive on line 1 is loaded as a normal flat file. You can migrate one file at a time.

How do I see what my agent actually receives?

Run the same query the stub uses:

# See exactly what SOUL.md resolves to
node ladybugdb/scripts/query.js --workspace --cypher \
  "MATCH (s:Soul {workspace:'openclaw'}) RETURN s.section AS section, s.content AS content ORDER BY s.priority"

# See what AGENTS.md resolves to
node ladybugdb/scripts/query.js --workspace --cypher \
  "MATCH (a:AgentConfig {workspace:'openclaw'}) RETURN a.key AS section, a.value AS content ORDER BY a.id"

The --workspace flag produces the same clean markdown output that gets injected into the system prompt.

What's the performance impact?

Negligible. In-process queries are sub-millisecond (0.11–0.41ms). CLI subprocess calls take ~100ms but are cached for 60+ seconds. See Performance Reference in the Admin Guide.

Can I query the skill graph from my agent's prompts?

Yes. Agents can run CLI queries as part of their task execution:

node ladybugdb/scripts/query.js "kubernetes monitoring"
node ladybugdb/scripts/query.js --skill cloudflare --hops 2

This is how cron jobs and automated workflows discover relevant skills at runtime.