CClawMetryDocs

Data & storage

The local DuckDB store#

One DuckDB file on your machine holds everything: events, sessions, spans, rollups and Guard state. It is the single data layer every feature reads and writes — there is no second source of truth.

Where it lives#

text
~/.clawmetry/          ClawMetry's own state directory
  local_store.duckdb   the store
  local_query.json     the daemon's query-server discovery file
  license.key          a self-hosted license, if any
  cloud_plan.json      the cached cloud plan
  hitl/                pause flag files
  reports/             Markdown you drop in for the reports browser
  evals/               eval suite YAML
VariableEffect
CLAWMETRY_HOMEMove the whole state directory
CLAWMETRY_LOCAL_STORE_PATHMove just the store file

One writer, many readers#

The sync daemon owns the writer lock, exclusively. Nothing else opens the file for writing — the dashboard process marks itself CLAWMETRY_ROLE=dashboard precisely so the store layer refuses to hand it a writer.

Readers go through the daemon's localhost query server, advertised in a discovery file:

~/.clawmetry/local_query.json
{"port": 51843, "token": "…", "pid": 4711}

A reader loads that file, checks the pid is alive, and posts to http://127.0.0.1:<port>/api/local/query with the bearer token. The dashboard, the MCP server and the cloud relay all do exactly this.

The pid check matters: a stale discovery file left by a crashed daemon would otherwise point every query at whatever process later took that port.

The rule this implies

A request handler must never read raw agent files. Opening ~/.openclaw/**.jsonl inside a handler works on a laptop and returns nothing in the cloud, where the container has no agent directories. Everything reads from the store, through the daemon.

What is in it#

Table groupContents
eventsThe normalised event stream — messages, tool calls, results, errors
sessionsOne row per session with start, end, totals and status
spansOpenTelemetry-shaped spans, for tracing and the agent graph
RollupsPer-session, per-runtime-per-day, per-model-per-day summaries
GuardSession statistics, egress hosts, policy actions, decision log
IntegrityThe tamper-evident hash chain

The rollups are why the dashboard is fast on a large store: pages read pre-aggregated rows rather than scanning the event table.

Sizing#

Growth is proportional to agent activity. A busy multi-runtime machine produces a few hundred megabytes over months; retention is what bounds it.

bash
clawmetry status --json | jq '.store'
curl -s localhost:8900/api/local/health | jq
VariableEffect
CLAWMETRY_LOCAL_MAX_GBSoft cap on store size
CLAWMETRY_AUTO_VACUUMAutomatic compaction
CLAWMETRY_RETENTION_DAYSRetention window, within tier limits

Reported size versus real size

DuckDB's own estimated size counts dead row versions, so a store that reports 1.6 GB may hold a fraction of that in live data. Compaction reclaims it. Judge by the file on disk and by whether compaction has run, not by the estimate.

Writes are idempotent#

Event ids are deterministic. Re-ingesting the same source produces primary-key no-ops rather than duplicates, which is what makes a replay — after a crash, after raising a session limit, after restoring a backup — safe.

Backing it up#

Stop the daemon first, or copy rather than move. DuckDB has WAL-like behaviour and a copy taken mid-write may not be consistent.

bash
clawmetry sync --restart   # or stop the service
cp ~/.clawmetry/local_store.duckdb ~/backups/clawmetry-$(date +%F).duckdb

For something you can read elsewhere without a DuckDB dependency, export instead. → Exports

Performance#

Two things dominate, and only one of them is the store:

Memory pressure. DuckDB keeps a buffer pool, and a machine that is swapping will make queries look slow when the store is fine. Before tuning anything, check actual memory pressure on the machine — this has been misdiagnosed as a store problem more than once.

Store size versus retention. A store holding a year of events on a laptop will be slower than one holding a month. If you do not need the history, do not keep it.

VariableEffect
CLAWMETRY_DUCKDB_MEMORY_LIMITDuckDB's memory limit
CLAWMETRY_DUCKDB_THREADSThread count
CLAWMETRY_LOCAL_FLUSH_SECSFlush cadence
CLAWMETRY_LOCAL_FLUSH_BATCHFlush batch size

If the store will not open#

bash
clawmetry verify-integrity --json

A store that reports as invalidated after an abrupt kill usually needs compaction rather than deletion. → Troubleshooting

Cookie preferences