Data Storage & Journal
This page covers where MindRoom keeps its data, what to back up, how to configure the event journal, and how to move or rebind the journal with mindroom journal adopt.
Data Persistence
MindRoom stores data in mindroom_data/ next to config.yaml by default; set MINDROOM_STORAGE_PATH to use another directory.
agents/*/sessions/andteams/*/sessions/- Conversation history (SQLite)agents/*/learning/- Per-agent Agno Learning state when learning is enabledagents/*/chroma/- Per-agent Mem0 ChromaDB storageprivate_instances/- The same per-agent directories for private agents, one tree per requester scopeknowledge_db/- Knowledge base vector storestracking/- Durable response and callback state, including the SQLite event journal, that prevents duplicate replies across restartscredentials/- Secrets synchronized from.envlogs/- Application logsmatrix_state.yaml- Matrix connection stateencryption_keys/- Matrix E2EE keys (if enabled)
Set MINDROOM_SESSION_STORAGE_PATH to move agent and team session databases to a separate root; learning and memory stay under the storage directory.
Backups
Back up the whole storage directory, and keep tracking/ on persistent storage.
When MINDROOM_SESSION_STORAGE_PATH is set in a container, mount that path on persistent storage and back it up too.
tracking/ keeps a small record of every handled event so restarts and resyncs never answer the same message twice.
These records are never pruned automatically, so size and monitor the volume for growth over the install's lifetime.
See Bot Runtime Architecture to inspect the records or remediate a corrupted one.
Incompatible session databases
If an upgraded Agno version requires session columns that an agent's or team's session database lacks, MindRoom moves that sessions/ directory aside to sessions.incompatible-<id>/ and starts a fresh conversation history.
The archive is kept intact for inspection or manual recovery; back it up and delete it when you no longer need it.
Event Journal
The event journal records which Matrix events were already handled and delivered, so restarts do not produce duplicate replies.
By default it is SQLite at <storage>/tracking/event_journal.db, a location that cannot be changed separately.
To use PostgreSQL, install the postgres extra (for example uvx --from 'mindroom[postgres]' mindroom run, or --extra postgres when syncing a source checkout), then select the backend and provide a connection URL:
| Field | Type | Default | Meaning |
|---|---|---|---|
backend |
sqlite or postgres |
sqlite |
Journal storage backend; a URL alone does not switch to PostgreSQL |
database_url_env |
string | MINDROOM_EVENT_CACHE_DATABASE_URL |
Variable holding the PostgreSQL URL, read from the process environment or the config-adjacent .env (process environment wins); custom names must be DATABASE_URL or end in _DATABASE_URL |
database_url |
string or null |
null |
Inline PostgreSQL URL that takes precedence over the variable |
Changes to event_journal apply after restarting MindRoom.
Read Journal binding before pointing an existing install at a different database.
Journal binding
Each install is bound to one event-journal database the first time it opens one, and records that binding in <storage>/tracking/event_journal_binding.json.
MindRoom refuses to start against any other journal, because another database would silently lose turn deduplication, delivery ownership, and recovery ownership.
A refused database is left untouched.
| Startup error contains | Cause | Fix |
|---|---|---|
has never been used by this install |
The configured database is new or empty, usually because the connection URL points somewhere new. | Check event_journal and the variable named by database_url_env and point them back at the bound database; adopt only if you want to start the journal's history fresh. |
is a different journal from the one this install is bound to |
The configured database belongs to another install, usually because the connection URL points at it. | Point event_journal back at the bound database, or adopt deliberately. |
could not be read or does not name a generation |
The binding file is corrupt or truncated. | Delete <storage>/tracking/event_journal_binding.json, then run mindroom journal adopt against the database you want; the file holds nothing the database does not. |
Do not adopt just because startup refused: a connection URL that drifted to a fresh database is the common cause, and adopting would abandon the real journal's history instead of finding it.
Adopting a journal
mindroom journal adopt binds the install to the event-journal database configured right now.
It is the deliberate override of the startup refusal and the only fix for a lost or corrupt binding file.
Adopting the database the install was already using keeps its history, but adopting a different database abandons the deduplication, delivery, and recovery history in the previously bound journal.
It asks for confirmation when the install is already bound, unless --yes is passed.
Stop MindRoom before adopting, because a running MindRoom keeps writing to the journal it started with and adopting under it would split the install's history across two databases.
Adoption refuses with Another process still has this install's event journal open while MindRoom is running; a crashed MindRoom does not block it.
--force adopts anyway; use it only when you are certain nothing is running, for example when several hosts share one storage root over a network filesystem, where the running check does not work across hosts.
If adoption fails, for example because the database is unreachable, the previous binding stays in place.
Moving a journal safely
A full copy of a journal database keeps its identity, so the binding accepts it without adoption. This also means a stale copy is accepted without complaint, even though every turn since it was taken is missing, so copy only from a stopped install.
- Stop MindRoom, and any
mindroom threads export --watchrunning against the same storage root. - Copy or dump-and-restore the database in full.
- Configure the destination PostgreSQL backend and URL, or move the SQLite journal together with its storage root.
- Start MindRoom.
Adopt instead of copying only when you accept beginning the journal's history fresh.