Skip to main content
Watches OpenClaw (~/.openclaw/agents/*/sessions/) and Claude Code (~/.claude/projects/) session files and ingests appends in micro-batches (default every 3s, tune with --flush 5). Combined with the search tail leg, a message one agent sends is searchable by every other agent within seconds — no index rebuild involved.

Why this exists

Multiple concurrent sessions need each other’s context. A schedule gives you interval freshness; hooks give you session-boundary freshness; watch gives you send/receive freshness — session B can ask “what did session A just decide?” while session A is still running:

How it stays cheap

  • Appends only: session JSONL files are append-only; a changed file is re-ingested whole and deduped by record_id anti-join (idempotent, no offset bookkeeping to corrupt).
  • DuckLake inlining: small inserts land inline in the SQLite catalog — no per-message Parquet churn. The next sync flushes them into Parquet during maintenance.
  • No embedding in the hot path: fresh rows are reachable via BM25 + the tail leg immediately; vectors catch up on the next sync.
  • Tail leg, not index rebuilds: search scans only bronze rows the sidecar hasn’t indexed yet (a recency-bounded anti-join), fused into results via RRF.

Concurrency

Same discipline as sync: a pid lock (logs/watch.lock) guarantees one watcher per instance, stale locks are reclaimed, and watcher inserts coexist with a running sync (WAL + busy-timeout on the catalog). As a daemon (auto on) it runs under launchd KeepAlive on macOS and a Restart=always systemd user service on Linux; remember loginctl enable-linger $USER on headless machines.