What is stored on your machine when OpenClaw has been running for a month: chats, tokens, or both?
Delia Santos
October 7, 2026
Both. After a month of OpenClaw, the Gateway host holds the chats and the tokens. Transcripts, tool output, and compaction summaries sit in a per-agent SQLite database under ~/.openclaw, and cold archives can hold older history beside it. Gateway tokens, channel bot tokens, model auth profiles, and OAuth refresh tokens sit in that same tree: config, a credentials directory, and two SQLite files. I have not found a default that deletes either pile because thirty days passed. A month of running is a month of accumulation, on the machine that runs the Gateway, not in the phone app.
OpenClaw is self-hosted. There is no OpenClaw cloud that is the copy of record. The secrets-and-storage page tells you to treat disk access as the trust boundary and to lock down ~/.openclaw. Anyone who can read that directory can read private messages and credentials. That is the fact to sit with before you put the Gateway on a shared login or a VPS snapshot you also send to offsite backup.
Where do the chats actually live?
In the per-agent database. The default path is ~/.openclaw/agents/<agent>/agent/openclaw-agent.sqlite. Session management splits that file into two kinds of rows. Session rows are mutable metadata: the current session id, last activity, toggles, and token counters. Transcript events are append-only. They store the conversation, tool calls, and compaction summaries, and they are what the Gateway uses to rebuild context for the next turn. Compaction does not mean the old text left the disk. The docs say compaction summaries and token measurements stay in the transcript without a separate checkpoint copy.
A second copy of older history can exist as cold archives. The database layout describes session_transcript_cold_archives and a default directory at ~/.openclaw/agents/<agent>/sessions/cold/, with compressed .jsonl.zst files. Those files are authoritative history, not a disposable cache. A month of busy chats can therefore be in the live SQLite rows and in cold files you will not see if you only look at the database size.
Older installs may still have sessions.json and JSONL transcripts under the agent sessions/ directory. Gateway startup does not import them. If it finds a legacy store, it refuses readiness and prints the doctor command rather than starting with empty history. openclaw doctor --fix, after you stop the Gateway and back up state, imports legacy rows and hot JSONL into SQLite. Until you do that, a month-old machine can be holding the new database and the old files at once. The pre-agent ~/.openclaw/sessions/ directory is no longer an implicit fallback.

Session rows also keep clocks that matter if you later try to prune. sessionStartedAt is when the current session id began. lastInteractionAt is the last user or channel interaction that extends idle life. updatedAt is the last time the row itself changed, which is useful for listing and a bad clock for “when did a human last speak.” Do not delete from updatedAt and call it a retention policy. The docs do say to prune old session transcripts and log files if you do not need long retention. They do not, in the pages I read, name a built-in thirty-day wipe. If you want a month to be the horizon, you have to make that choice. The product will not make it for you.
Where do the tokens live?
“Tokens” in this question means secrets, not the usage counters in a session row. Those counters are numbers about how much context a turn used. The secrets are the strings that let the Gateway act.
The secrets page lays out the tree:
openclaw.jsoncan hold gateway tokens, remote gateway tokens, provider settings, and allowlists.credentials/holds channel credentials, including WhatsApp’screds.jsonunder a WhatsApp directory, pairing allowlists from older layouts, and legacy OAuth import files such asoauth.json.state/openclaw.sqliteis the shared control plane: runtime state, native MCP OAuth access and refresh tokens, dynamic client registration secrets, and discovery state.- The per-agent
openclaw-agent.sqliteholdsauth_profile_storerows: model auth profiles for that agent.
Channel tokens have named homes. A Telegram bot token can be in config, in the environment, or in channels.telegram.tokenFile, and that file must be a regular file. Symlinks are rejected. Discord can use config, the environment, or a secret reference. Slack tokens are config or environment under channels.slack. A month of “it just works” often means the token was written into openclaw.json on day one and is still there, in plaintext, next to the chats.

OAuth is split on purpose. Shared credentials live in ~/.openclaw/state/openclaw.sqlite. Agent-local overrides and routing state live in the agent database: auth_profile_store for the credential rows, auth_profile_state for order, last-good, cooldown, and usage. Personal accounts added from Profile or models accounts login use private records in the shared state database. Only a selected personal profile is loaded for a run. Ordinary shared-account reads do not enumerate those records. A refresh writes back to the store that owns the profile. If the agent was reading a shared OAuth profile, the refresh updates that shared owner. It does not clone the refresh token into the agent just because the agent used it. Copy flows skip refresh tokens by default, because some providers rotate or invalidate them after use.
Profiles store an expires time. If it is still in the future, OpenClaw uses the stored access token. If it has expired, it refreshes and saves the new credentials back. After a month, you should expect refreshed access tokens, not the original access token from install day, and you should expect the refresh token to still be on disk. Expiration of an access token is not deletion of the credential.
Pairing state is in the shared SQLite file too: pending requests and approved senders. Older gateways wrote allow-from JSON under credentials/. The pairing docs say channels on the pairing API read the SQLite rows and do not merge those legacy files, and that normal startup leaves the JSON in place until openclaw doctor --fix imports and removes it. A month later, both can still be on the disk if you never ran doctor. The live decision is the database. The leftover JSON is still a list of who was allowed. Delete it only through that import, or after you have confirmed the SQLite rows replaced it. Hand-deleting the file you hope is unused is how people lock themselves out, or how they leave the real allowlist untouched and think they cleaned up.
What is on the phone, and what is not?
The phone is not this archive. The iPhone app keeps a small read-only cache of recent transcripts per paired Gateway so a cold open can paint the last thread, and an outbox of up to 50 unsent texts that expire after 48 hours offline. Reset or forget clears that cache. Assistant images in that cache are not the bytes. They are pointers at short-lived Gateway artifact URLs. The phone app does not run the model or host the Gateway, and it does not become the place a month of chats and tokens reside. Lose the phone and you still have the host. Lose the host, or a backup of ~/.openclaw, and the phone’s last screen is not a restore.
Device pairing tokens for the phone do live on the Gateway, in the shared state database, bounded to the approved role. A stray token outside that role does not create access. That is still a secret on the host. Unpairing is a host-side act. Wiping the phone does not shred the Gateway’s copy of the device record.
What else accumulates that is neither a chat nor a token?
Logs. The secrets page says log and transcript redaction is always on and cannot be disabled. You can add logging.redactPatterns for tokens, hostnames, and internal URLs in your environment. Redaction is not the same as absence. A log line that has been scrubbed can still describe that a tool ran, against which host, at what time. When you need to share diagnostics, the documented paste is openclaw status --all, which is redacted, not a raw log file and not a SQLite dump.
Tool output inside transcripts is the part people forget when they say “it’s just chat.” A shell listing, a file the agent read, a web page it fetched, a WhatsApp session’s working state: if it entered the turn, the transcript store is allowed to keep it. Memory indexes live in the same per-agent database. Meeting captures, if you use them, are three tables in the shared state database, separate from the agent conversation. Markdown or JSON under a transcripts directory are exports, not the runtime store. Exporting feels like the cleanup. It is a second copy.
WhatsApp is called out because it stores more on disk than a bot-token channel. The channel overview says QR pairing keeps more state, and the secrets page points at creds.json under the WhatsApp credentials directory. A month of WhatsApp is not just message text. It is a logged-in session on that host. Treat that file like a logged-in browser profile.
What should you leave human?
Leave the decision to retain. The Gateway will keep chats so the next turn has context, and it will keep tokens so the next turn can authenticate. Neither is a surprise, and neither expires because a calendar month ended. If a backup job copies ~/.openclaw to a disk other people can mount, that backup is a second copy of your messages and your provider keys. Exclude it, encrypt it, or stop pretending the closet computer is the only place the data lives.
Leave pruning as an explicit job, not a hope. The docs tell you to prune old transcripts and logs when you do not need long retention. They also tell you to stop the Gateway and back up before doctor migrations. I am not going to invent a delete command the storage page did not give me. Read the session store page and the cold-archive page on docs.openclaw.ai before you remove files by hand. Cold .jsonl.zst files are authoritative history. Removing them because they look like cache is how you lose the month you thought was only in SQLite.
Leave provider keys and channel tokens out of screenshots and out of git. openclaw.json is a config file that is allowed to contain secrets. A dotfiles repo that includes it is a published bot token. Prefer the env, file, and secret-reference paths the channel pages already describe, and still assume the SQLite auth stores contain the live credentials after a refresh.
A month of OpenClaw on your hardware is a month of chats and a month of tokens, in ~/.openclaw, on the Gateway host. The phone holds a short cache. The model provider holds whatever that provider’s own policy says about prompts you sent, which is a different machine and not something OpenClaw’s disk layout can answer. For the copy you actually control, assume both, and assume they are still there until you have pruned them on purpose.