Skip to main content
Clawboo’s persistent configuration is a single JSON file (settings.json) plus a small set of files Clawboo owns under its own state directory. This page documents the on-disk shapes, the path-resolution rules, and the OpenClaw files Clawboo reads (but does not treat as its own state). For the environment variables that override these locations, see Environment variables.

At a glance

ConcernDefault locationOverrideResolver
Clawboo state dir~/.clawboo/CLAWBOO_HOME (with ~ expansion)resolveClawbooDir()
Settings~/.clawboo/settings.jsonfollows CLAWBOO_HOMEresolveSettingsPath()
SQLite DB (server)~/.clawboo/clawboo.dbfollows CLAWBOO_HOMEgetDbPath()
SQLite DB (MCP stdio bins)~/.openclaw/clawboo/clawboo.dbCLAWBOO_DB_PATHdefaultDbPath()
Secrets vault~/.clawboo/secrets/CLAWBOO_SECRETS_MASTER_KEY (key only)getVaultPaths()
OpenClaw interop reads~/.openclaw/OPENCLAW_STATE_DIRresolveStateDir()
Clawboo writes only under its own state directory (~/.clawboo by default). The exception is OpenClaw onboarding: when a user configures the OpenClaw runtime through the wizard, Clawboo writes openclaw.json and .env into OpenClaw’s state directory on the user’s behalf. Outside that flow, OpenClaw’s directory is read-only interop.

settings.json

The persisted settings file. Read by loadSettings(), written by saveSettings(), and surfaced (token-redacted) by GET /api/settings.
  • Path: resolveSettingsPath()<resolveClawbooDir()>/settings.json~/.clawboo/settings.json by default.
  • Created: lazily on the first saveSettings() call (the directory is mkdir -p’d first). Missing or unparseable file → defaults.
  • In-memory shape (ClawbooSettings):
interface ClawbooSettings {
  gatewayUrl: string          // upstream OpenClaw Gateway WebSocket URL
  gatewayToken: string        // upstream auth token (never returned to the browser)
  studioAccessToken?: string  // optional access-gate token
  firstRunDismissedAt?: number // epoch ms the user dismissed the first-run nudge
}
  • On-disk shape: the gateway URL/token are nested under a gateway object; studioAccessToken and firstRunDismissedAt are top-level. saveSettings() only writes the fields the caller explicitly provides; omitted fields are left untouched.
{
  "gateway": {
    "url": "ws://localhost:18789",
    "token": "gateway-auth-token-value"
  },
  "studioAccessToken": "optional-access-gate-token",
  "firstRunDismissedAt": 1717286400000
}

Field reference

FieldOn-disk keyTypeDefaultNotes
gatewayUrlgateway.urlstringws://localhost:18789Falls back to the default URL when unset. Validated as ws:///wss:// on write via POST /api/settings.
gatewayTokengateway.tokenstring""Never returned by GET /api/settings; only hasToken: boolean is exposed. Resolved through the template chain below.
studioAccessTokenstudioAccessTokenstring | undefinedundefinedOptional token for the access gate (see Security).
firstRunDismissedAtfirstRunDismissedAtnumber | undefinedundefinedSet when the user dismisses the first-run nudge; surfaced by GET /api/settings as firstRunDismissedAt (number or null).

Token resolution chain

gatewayToken is resolved at read time, not stored verbatim in every case:
  1. If gateway.token is a template token like ${GATEWAY_AUTH_TOKEN}, it is resolved from process.env first, then from <resolveStateDir()>/.env.
  2. If no usable token results, loadSettings() falls back to OpenClaw’s openclaw.json (gateway.auth.token + gateway.port), resolving the same template syntax and synthesizing ws://localhost:<port>.
  3. Otherwise the literal value is used; gatewayUrl falls back to ws://localhost:18789.
This bridges OpenClaw’s secret management (its .env) with Clawboo’s proxy auth; it is not a dev-project .env pattern.

State directory (~/.clawboo)

Resolved by resolveClawbooDir(). The override CLAWBOO_HOME is ~-expanded and resolved to an absolute path; otherwise the directory is <homedir>/.clawboo. Clawboo owns everything under this directory. The OpenClaw runtime dependency is unchanged; only the file home is Clawboo’s own (matching how Codex and Claude Code each own their dir).
PathOwner / writerPurpose
clawboo.dbgetDbPath() (Express server)SQLite database: agent registry, board, memory, tools, governance, the event log, and all other tables. WAL mode.
settings.jsonresolveSettingsPath()Persisted settings.
api-port.txtportUtils (writeApiPortFile/readApiPortFile)Single line: the integer port the API bound to. Written on successful bind, removed on graceful shutdown. Read by the CLI, the Vite dev proxy, and e2e helpers.
proxy-device-identity.jsongateway-proxy (loadOrCreateProxyDeviceIdentity)The same-origin proxy’s persistent Ed25519 keypair (holds the private key) for server-side Gateway device auth.
gateway.pidprocessManager (writeGatewayPid/removeGatewayPid)JSON { pid, port, startedAt } for the managed OpenClaw Gateway process.
worktrees/<repo-hash>/worktrees.ts (worktreeRootForRepo)Per-task git worktrees + the system-of-record scaffold, namespaced by a SHA-1 hash of the repo path. Outside the user’s repo tree so they never pollute its git status.
reviews/<repo-hash>/worktrees.ts (reviewRootForRepo)Detached, read-only review checkouts for the builder≠judge critic gate.
secrets/secretsVault.tsThe encrypted runtime-credential vault.
runtimes/<runtimeId>/<agentId>/runtimes/identityHome.ts (runtimeIdentityHomePath)Per-identity persistent runtime homes (e.g. Hermes’s skills/memory/session state), one per agent. The agent id is sanitized to a single path segment (dots excluded → traversal-impossible; empty id → _default).
runtimes/hermes/capabilitySource/hermes.tsThe Hermes home scanned for native SKILL.md skills + mcp.json (observe-only capability read).

The two DB-path resolvers

There are two distinct resolvers for the SQLite path, and they differ:
  • getDbPath() (apps/web/server/lib/db.ts): used by the Express server and the worktree/board code. Returns <resolveClawbooDir()>/clawboo.db~/.clawboo/clawboo.db. It does not read CLAWBOO_DB_PATH; it follows CLAWBOO_HOME.
  • defaultDbPath() (@clawboo/db): used by out-of-process consumers (the MCP stdio bins spawned by external runtimes). Honors CLAWBOO_DB_PATH when set, otherwise returns the legacy ~/.openclaw/clawboo/clawboo.db.
The MCP stdio bins must open the same SQLite file the server serves. When CLAWBOO_HOME is set to a non-default location (e.g. a sandbox), set CLAWBOO_DB_PATH to that same clawboo.db so the bins and the server agree. The multi-process WAL recipe is what makes a shared file safe.

Secrets vault

Encrypts each runtime provider key at rest with AES-256-GCM under a local master key. This is defense in depth, not attacker-proof: a process running as the user can read the master key. The vault defeats casual viewing and a leaked-disk scenario.
  • Directory: <resolveClawbooDir()>/secrets/, created with mode 0700 (best effort; advisory on Windows).
  • Master key: secrets/master.key (32 bytes, base64-encoded, mode 0600). Auto-generated on first use if absent.
  • Vault: secrets/runtime-keys.json, mode 0600, keyed by env-var name:
{
  "ANTHROPIC_API_KEY": { "iv": "...", "tag": "...", "ciphertext": "..." },
  "OPENROUTER_API_KEY": { "iv": "...", "tag": "...", "ciphertext": "..." }
}

Master key

AspectBehavior
OverrideCLAWBOO_SECRETS_MASTER_KEY takes priority over the on-disk key file.
Accepted forms64 hex characters, base64, or a raw 32-character string, all decoding to exactly 32 bytes.
Invalid overrideThrows loudly (the message lists the accepted forms).
Missing on-disk keyGenerated as 32 random bytes and persisted.
Wrong / rotated / lost keyFails closed; getRuntimeSecret returns null rather than throwing.

Runtime-key resolution chain

resolveRuntimeKey(envVar) is the one place a secret value is read (callers put it straight into a spawned child’s environment, never a log, response, audit, or SQLite). Highest priority first:
  1. process.env[envVar]
  2. the encrypted vault (secrets/runtime-keys.json)
  3. OpenClaw’s <resolveStateDir()>/.env (so an existing OpenClaw provider key, e.g. ANTHROPIC_API_KEY, is reused automatically)

OpenClaw interop reads (~/.openclaw)

OpenClaw’s state directory is located by resolveStateDir(). It honors OPENCLAW_STATE_DIR (and the legacy MOLTBOT_STATE_DIR / CLAWDBOT_STATE_DIR); otherwise it returns the first existing of ~/.openclaw, ~/.clawdbot, ~/.moltbot, defaulting to ~/.openclaw. Clawboo reads these OpenClaw files:
FileRead byPurpose
openclaw.jsonloadSettings(), system.ts (status/config endpoints)Gateway URL/token/port defaults; tools and mcp config inspected/patched by the System panel endpoints.
.envreadOpenclawEnvVar(), token-template resolutionLowest-priority provider-key fallback; template-token (${...}) resolution.
agents/<id>/agent/auth-profiles.jsonsystem.ts (provider-detection)Per-agent provider keys OpenClaw stores outside .env.
OPENCLAW_CONFIG_PATH appears in design-intent notes but is not read by current code; the config path is always derived as <resolveStateDir()>/openclaw.json.

See also