How it works
One app, two kinds of server
┌──────────────────────────────┐
│ Chronicler app │
│ (one download, either mode) │
└───────┬──────────────┬───────┘
Cloud mode │ │ Local mode
▼ ▼
┌────────────────┐ ┌──────────────────────┐
│ Our hosted │ │ Your Docker stack │
│ service │ │ on your machine │
└────────────────┘ └──────────────────────┘
There are no separate builds. Which server the app talks to is a setting in Settings → Connection, stored on that machine, and switching signs you out — Cloud accounts and self-hosted accounts are entirely separate, even with the same email address.
The server, by contrast, decides what it is when it's deployed. A self-hosted server always serves exactly one organisation, never allows self-service sign-up, and always requires a licence. Those aren't settings.
From a question to an answer
Upload
Text is extracted from the file. Scanned pages and images go through OCR. There are two engines: the standard one, which is fast, and an AI-assisted one you can choose per upload for pages the standard engine garbles — typically images of tables. Spreadsheets skip OCR entirely and are parsed row by row.
Index
The text is split into passages, and each passage is turned into a vector by the embedding model. Those vectors are stored in PostgreSQL using the pgvector extension — there's no separate search database to run.
Ask
Your question is embedded the same way and matched against those passages, within whatever scope you selected (everything, a collection, or specific documents).
Answer
The best-matching passages and your question go to the generation model, which writes the answer. The passages it used come back as citations.
On a self-hosted server, every one of those steps happens in your containers. The
generation model runs in the ollama container on your CPU or GPU; the embedding
model runs inside the backend and ships with the image, so it works with no
internet access.
Where things are stored
| Data | Lives in |
|---|---|
| Accounts, collections, conversations, document text and vectors | PostgreSQL (postgres_data) |
| The original uploaded files, backups, the install identity | backend_uploads |
| Downloaded language models | ollama_data |
What the server talks to
A self-hosted server makes only two kinds of outbound connection:
api.chroniclerlm.com, every 30 minutes, to verify the licence. It sends the key and an install identifier — no document content, no user data. Signed responses, so pointing this elsewhere doesn't work.- Docker Hub and GitHub, when you install or update, for images and the compose file.
There's no analytics, no crash reporting to us, and no document data leaving the machine.
The schema updates itself
The backend runs its database migrations at startup. Postgres starts empty and the backend builds the schema; on an update, it dumps the database before changing the schema and refuses to continue if that dump fails. You never run migrations by hand.
Further reading
- Overview — the containers and ports
- Configuration reference — every setting
- Security and networking — exposing it safely