Download the zip
Grab chronicledb-v0.2.3.zip from the v0.2.3 release. The zip is self-contained — no git, no Node toolchain, no shell scripts. node_modules is bundled; the internal folder layout mirrors SillyTavern's so files land where ST expects them when you extract in Step 02.
Or browse all assets on the latest release page. The asset name follows the pattern chronicledb-vX.Y.Z.zip — the download button above is hardcoded to the current release and gets bumped each tag.
plugins/chronicle-db/— server plugin with bundlednode_modules(incl.@electric-sql/pglitefor the embedded DB)public/scripts/extensions/third-party/chronicle-db/— UI extension (the drawer you'll see in Step 04)
Downloads. Don't double-click to "open" it — that opens the zip in-place inside Explorer's zip viewer, which is not the same as extracting. Step 02 has the right-click flow.
Prefer running your own Postgres and pulling updates via git pull? See the Advanced install section at the bottom — install.sh / install.ps1 are still supported there.
Extract into SillyTavern & enable plugins
Extract the zip so its two folders land on top of your SillyTavern install, then flip one line in config.yaml. That's the whole install.
A. Extract the zip into your SillyTavern folder
Two options — pick whichever you're comfortable with.
Finder: double-click chronicledb-v0.2.3.zip in Downloads. That creates a chronicledb-v0.2.3/ folder alongside it. Open that folder; you'll see plugins/ and public/ inside. Drag both into your SillyTavern folder — macOS will ask to merge; choose Merge.
Terminal:
cd ~/SillyTavern
unzip -o ~/Downloads/chronicledb-v0.2.3.zip
-o overwrites any existing files without prompting, which is what you want when you're upgrading a previous install.
From a terminal inside your SillyTavern folder:
cd ~/SillyTavern
unzip -o ~/Downloads/chronicledb-v0.2.3.zip
-o overwrites in place so upgrades from a previous ChronicleDB install don't need to be uninstalled first.
unzip? sudo apt install unzip on Debian/Ubuntu, or sudo dnf install unzip on Fedora.
- In File Explorer, open the folder where you saved the zip (e.g.
Downloads). - Right-click
chronicledb-v0.2.3.zip→ Extract All... - In the Extract dialog, change the destination to the root of your SillyTavern install — e.g.
C:\Users\YOU\SillyTavernor wherever you runStart.batfrom. Click Extract. - Windows will prompt to merge the
pluginsandpublicfolders with the existing ones — choose Replace the files in the destination.
PowerShell equivalent if you prefer a one-liner:
Expand-Archive -Path $HOME\Downloads\chronicledb-v0.2.3.zip -DestinationPath $HOME\SillyTavern -Force
<ST>/plugins/chronicle-db/— with a populatednode_modules/inside<ST>/public/scripts/extensions/third-party/chronicle-db/
If those two paths exist, extraction worked. Nothing else in your ST folder should have changed.
B. Enable server plugins
SillyTavern only loads server plugins when one line is flipped in config.yaml at your ST install's root. Open it in any text editor:
# ...other settings above...
enableServerPlugins: true
# ...other settings below...
If the key is already there and set to true, you're done — save and skip to Step 03. If it's false or missing, set/add it, save, and move on.
config.yaml? Same folder as Start.bat / start.sh — the root of your SillyTavern install, not inside data/. Create it from default/config.yaml if you've never edited it before.
install.sh, the zip install doesn't patch config.yaml for you — it's a plain file copy. Miss this and ST silently ignores the plugin on boot (you'll notice in Step 03).
Restart SillyTavern
Stop ST, start it again. The server plugin initializes on boot, so without a restart the new code doesn't get loaded. You should see these lines in your terminal:
Users will be able to log in.
Extensions loaded.
[ChronicleDB] Initializing server plugin...
[ChronicleDB] Mind map path: /path/to/chronicledb/src/ui
[ChronicleDB] Server plugin ready.
SillyTavern is listening on IPv4: 0.0.0.0:8000
If you don't see the three [ChronicleDB] lines, something stopped the plugin from loading. Check config.yaml in your SillyTavern root:
enableServerPlugins: true
basicAuthMode: true
enableServerPlugins is missing or false, the plugin is being silently ignored. Re-check Step 02B — set it to true, save, and restart ST again. A SillyTavern update can also revert it during a config merge, so this is worth re-checking after any ST upgrade.
Open the settings panel
Inside SillyTavern, click the Extensions icon in the top bar (the one that looks like a stack of blocks), then scroll through the extensions list until you find the ChronicleDB drawer. Click its header to expand.
Once expanded, the top of the drawer shows your connection status:
<ST>/plugins/chronicle-db/pgdata on first connect — no fields to fill in, no external DB to stand up. If you see Not connected or a Checking… that never resolves, head to Troubleshooting.
Database fields (optional — external Postgres only)
<ST>/plugins/chronicle-db/pgdata on first connect, and your status pill should already be green. This step only matters if you deliberately flipped Storage backend to External Postgres (e.g. you're running your own Postgres server, or you're using a cloud DB like Neon / Supabase).
If you are on external Postgres, fill in where it lives and hit Connect & initialize:
Embedded — PGlite by default — nothing to fill in. Flip to External Postgres to reveal the connection fields below.
localhost, port 5432, db chronicledb, user is your OS username, password is blank (Postgres uses local trust auth by default). The Advanced install section runs install.sh which sets this up end-to-end.
ep-xxx.region.aws.neon.tech, port 5432, db = whatever name appears after the last / in the connection string, user + password from the Neon Dashboard's Direct connection string (not the Pooler). Neon requires SSL — ChronicleDB enables it automatically when the host isn't localhost.
db.xxxxxxxxxxxx.supabase.co, port 5432 (the direct connection, not the pooler on 6543), db postgres, user postgres, password = whatever you set when creating the project. The pooler on 6543 runs in transaction mode and breaks DDL + pgvector init. Full step-by-step for both Neon and Supabase is in the Advanced install section.
characters/ and chats/ on its own. Leave blank otherwise.
When you click Connect & initialize, the plugin runs CREATE EXTENSION IF NOT EXISTS vector and pg_trgm, then builds the full schema (tables, indexes, constraints). On a cloud DB this is the moment you'll find out if your user has the CREATE EXTENSION privilege — Neon and Supabase both grant it by default.
LLM + embedding config
Two model blocks. The memory model reads your chats and pulls structured memory out — a cheap, fast model is fine; you do NOT need a frontier model here. The embedding model converts text into 768-dim vectors for semantic search.
- Memory model:
gemini-3.1-flash-lite-preview - Embedding model:
gemini-embedding-2-preview(covered in the next block)
Both fall under the Gemini free tier — see the Gemini pricing page (the "Free Tier" column) for current rate limits. Get a key at aistudio.google.com/apikey — it takes ~30 seconds, no credit card.
/v1 base, paste the key, set the model name exactly as your provider lists it.
vector(768) columns are baked in. Pick a model that natively outputs 768 dims, or one that honors a dimensions parameter — Gemini's gemini-embedding-2-preview, OpenAI's text-embedding-3-small / 3-large, and Vertex's text-embedding-004 / 005 all qualify.
Memory type toggles
Four switches gate what the extractor writes to the DB. All on by default; turn off any you don't want. These only affect future extractions — existing memory stays put.
| Toggle | What it captures | When to turn off |
|---|---|---|
| Relationships | Directional sentiment + intensity between every pair of characters who interact, with a short description. | Solo-character RPs with no inter-character dynamics. |
| Events & timeline | What happened each batch, with significance, participants, verbatim source quote, and causal chains. | Pure character-study chats with no plot. |
| What each character knows | Per-character epistemic state — what they've witnessed, been told, or explicitly don't know. | Omniscient narration where no one is meaningfully ignorant. |
| World state | Key-value facts about the setting (weather, faction standings, item ownership) with validity windows. | Dialogue-driven chats with minimal world detail. |
Behavior knobs
How memory gets built while you chat and how much of it lands in your prompt. Safe defaults; touch when you have a reason.
| Knob | Default | What it does |
|---|---|---|
| Auto-build memory | on | Every reply automatically updates memory. Turn off if you only want memory from chats you explicitly ingest. |
| Update every N replies | 1 | How often the extractor fires. 1 = every message; 3 = every third. Higher = fewer API calls, coarser event-granularity. |
| Memory budget (tokens) | 3000 | Max tokens in the injected memory block. Higher = more memory in context, fewer tokens for the actual story. |
| Keep last N raw | 5 | Padding window. The latest N messages stay in ST's native context and aren't ingested yet. Lets you swipe / edit without triggering cleanup. |
| Refresh arcs every N | 30 | Incremental Louvain rebuild of the story-arc hierarchy, fires every N new events. Title-reuse makes the per-fire LLM cost near zero. 0 disables — only manual full-chat ingest rebuilds arcs. |
Per-character memory
Each character has their own memory scope. Three modes plus a per-character chat picker that lets you opt specific past chats in or out. These settings are per-character, not global.
| Mode | Effect |
|---|---|
| Persistent | Character remembers across every checked chat. The inject pulls from all of them, scoped to this character's participations. |
| Isolated | Fresh slate per chat. No cross-pollination. New extractions still write to the DB, but retrieval only surfaces this-chat data. |
| Read-only | Reads existing memory but doesn't add new extractions. Useful when you want to test / read-through an archived story without polluting it. |
You're done
That's it. Open a chat, send a message, watch the memory block fire in your terminal or in SillyTavern's chat completion log. Your next few messages will be light on memory (the DB is still bootstrapping); after 5-10 turns the inject becomes rich.
Assembling… — 1,247 tokens / 3,000 budget
Indexing… — 3 new memory_embeddings
Where to go next
- ▸ Click Open mind map in the drawer — it'll launch a 3D WebGL graph of every character, event, and plot thread this chat has accumulated.
- ▸ Check Debug: recent LLM calls at the bottom of the drawer if something feels off. Every extraction and embedding call shows up with status, latency, and error.
- ▸ To import an existing chat history: Character memory → Build memory from all.
- ▸ Questions or bugs: GitHub Issues.
Advanced install: Postgres & git-based updates
The zip install covers almost every case — don't use this section unless you have a specific reason. Pick the advanced path if:
- You want a full local PostgreSQL 17 + pgvector rather than the embedded PGlite (larger datasets, concurrent access, want to poke at the DB with
psql). - You want to follow the project's
masterbranch viagit pullinstead of waiting for a tagged zip. - You want a cloud Postgres (Neon / Supabase) wired in from the start, with
install.sh --skip-postgreshandling everything except the DB itself.
Otherwise, stay on the zip install above — it's simpler and has fewer moving parts.
A. Clone the repo
git once you install Git for Windows. Whether you need WSL depends on your database choice in step B — a cloud DB skips WSL entirely.
Two ways: git clone (recommended — easy to pull updates later) or download the repo ZIP (no git required). Either way you'll end up with the repo on disk, and step B will run the installer from there.
Open a terminal and run:
git clone https://github.com/alani-fan-club/chronicledb ~/.chronicledb
cd ~/.chronicledb
~/.chronicledb is the default the installer expects. Put it anywhere you like — just remember the path for step B.
Updating later: cd ~/.chronicledb && git pull, then re-run install.sh / install.ps1 and restart SillyTavern.
If you don't have git installed, grab a source ZIP from GitHub (this is not the release zip — it's the raw repo):
- Go to github.com/alani-fan-club/chronicledb
- Click the green Code button → Download ZIP
- Unzip it somewhere you'll remember — e.g.
~/.chronicledb:
unzip ~/Downloads/chronicledb-master.zip -d ~/
mv ~/chronicledb-master ~/.chronicledb
cd ~/.chronicledb
Updating later without git means repeating this download + unzip dance. Consider installing git first if you plan to stay on master.
B. Run the installer (local Postgres or cloud DB)
Two routes. If you want a local Postgres, run install.sh — it sets up everything in one shot (Postgres, symlinks into ST, config.yaml patch). If you'd rather use a free cloud DB, skip the local Postgres install and do the wiring manually.
Open PowerShell (regular, not Administrator) and run:
irm https://raw.githubusercontent.com/alani-fan-club/chronicledb/master/install.ps1 | iex
No WSL, no admin, no Postgres install — the embedded PGlite database lives entirely inside the plugin. The installer junctions the plugin and UI extension into your SillyTavern folder (junctions, unlike symlinks, don't need elevation or Developer Mode).
From inside the ChronicleDB directory you cloned in step A:
bash install.sh
The script will prompt a few times. Answer yes to each to keep going. Here's what it does and what you'll see:
[chronicledb] Platform: macos
[chronicledb] Found SillyTavern at /Users/you/SillyTavern
[chronicledb] PostgreSQL is not installed.
[?] Install PostgreSQL 17 + pgvector via Homebrew now? [Y/n] y
[+] Running: brew install postgresql@17 pgvector
[+] Running: brew services start postgresql@17
[+] npm install in server-plugin ...
[+] Symlinking plugin into SillyTavern ...
[+] Symlinking UI extension ...
[+] Enabling enableServerPlugins in config.yaml ...
[+] Creating database 'chronicledb' ...
[+] Enabling extensions (vector, pg_trgm) ...
[ok] Install complete.
Database: chronicledb @ localhost:5432 as $USER
Plugin: ~/SillyTavern/.../third-party/chronicle-db
[chronicledb] Platform: linux
[chronicledb] Found SillyTavern at /home/you/SillyTavern
[chronicledb] PostgreSQL is not installed.
[?] Install PostgreSQL 17 + pgvector via apt now? (will sudo) [Y/n] y
[+] Running: sudo apt-get install postgresql-17 postgresql-17-pgvector
[+] Running: sudo systemctl start postgresql
[+] Creating Postgres role for current user 'you' ...
[+] npm install in server-plugin ...
[+] Symlinking plugin into SillyTavern ...
[+] Symlinking UI extension ...
[+] Enabling enableServerPlugins in config.yaml ...
[+] Creating database 'chronicledb' ...
[+] Enabling extensions (vector, pg_trgm) ...
[ok] Install complete.
Database: chronicledb @ localhost:5432 as you
Plugin: ~/SillyTavern/.../third-party/chronicle-db
sudos to install Postgres via apt and create your OS user's Postgres role.
Settings for Step 05: host localhost, port 5432, database chronicledb, user = your system username, no password.
Set up a free cloud Postgres first, then run install.sh with the --skip-postgres flag — it'll do the npm install, ST symlinks, and config.yaml patch without touching a local database.
B1. Create a cloud Postgres
Pick one. Both have free tiers and ship pgvector. Whichever you pick, you'll end up with a connection string of the form postgresql://USER:PASSWORD@HOST:PORT/DATABASE — map the five fields from that into the ST settings panel in Step 05.
Supabase — step by step
- Sign up at supabase.com and create a new project. Set a database password — save it somewhere, Supabase only shows it once.
- Wait for the project to provision (~1 min).
- Go to Database → Extensions. Toggle on both
vector(pgvector) andpg_trgm. Without these the schema init fails at theCREATE EXTENSIONlines. - Open Project Settings → Database → Connection string. Copy the URI tab. It looks like:
postgresql://postgres:[YOUR-PASSWORD]@db.xxxxxxxxxxxx.supabase.co:5432/postgres - The five fields you'll paste into ST's Database panel:
Host db.xxxxxxxxxxxx.supabase.coPort 5432(direct connection — not 6543, the pooler)Database postgresUser postgresPassword the one you saved in step 1
- Use port 5432, not 6543. 6543 is the transaction pooler (PgBouncer); pgvector and the schema-init transactions ChronicleDB runs at startup don't behave under it. Direct on 5432 is what you want.
- Free tier pauses after a week of inactivity. The first request after a pause hangs ~30s while the project wakes up. ChronicleDB's reconnect logic catches it but the status badge will flicker red briefly — that's normal.
Neon — step by step
- Sign up at neon.tech and create a project. Default database name is fine.
- Open the SQL Editor and run:
CREATE EXTENSION vector; CREATE EXTENSION pg_trgm; - From the project Dashboard, copy the Connection string (Direct, not Pooler):
postgresql://USER:PASSWORD@ep-xxxxx.region.aws.neon.tech/dbname - Map into ST's Database panel: host =
ep-xxxxx.region.aws.neon.tech, port =5432, database = whatever name you see after the last/, user + password = whatever's between://and@.
B2. Wire the plugin into SillyTavern
From the directory you cloned in step A:
bash install.sh --skip-postgres
In a regular PowerShell window:
# Download once so we can pass the flag (iex doesn't forward args)
iwr https://raw.githubusercontent.com/alani-fan-club/chronicledb/master/install.ps1 -OutFile $env:TEMP\install.ps1
& $env:TEMP\install.ps1 -ExternalPostgres
Same installer as the local path, just with -ExternalPostgres so it skips the embedded PGlite default. Paste the cloud DB host/port/db/user/password into the ST settings panel after restart.
[chronicledb] Platform: macos
[chronicledb] Found SillyTavern at /Users/you/SillyTavern
[chronicledb] Node v20.11.0
[chronicledb] Skipping local PostgreSQL setup (--skip-postgres)
[chronicledb] Skipping pgvector check (--skip-postgres)
[+] npm install in server-plugin ...
[+] Symlinking plugin into SillyTavern ...
[+] Symlinking UI extension ...
[+] Enabling enableServerPlugins in config.yaml ...
[chronicledb] Skipping database creation (--skip-postgres).
[chronicledb] Paste your cloud DB connection info into the ST
[chronicledb] settings panel after restart.
[ok] Install complete.
SKIP_POSTGRES=1 as an env var works too if you prefer.
After either branch completes, come back to Step 03 and continue from the restart.
Common problems
Install gone sideways? Almost every report so far has been one of the issues below. Each one says what the symptom looks like, why it happens, and the exact fix.
Mind map character sidebar is empty (no character cards loading)
Symptom: The mind map opens, you see graph nodes for whatever extraction has produced, but the Characters sidebar on the right shows only "SHOW ALL" with nothing under it.
Cause: The plugin reads character cards from <ST data root>/characters/*.png. It auto-detects the data root from process.cwd(), which is wrong on Windows when SillyTavern is launched via a shortcut or batch file that doesn't cd into the ST install directory first — cwd ends up being something like C:\Windows\system32 instead of the ST root.
Fix: In the ChronicleDB settings panel, fill in the SillyTavern data root (optional) field with the absolute path to your data directory. Examples:
- Standard install:
C:\Users\YOU\SillyTavern\data\default-user - SillyTavern Launcher:
C:\Users\YOU\SillyTavern-Launcher\SillyTavern\data\default-user - macOS / Linux:
~/SillyTavern/data/default-user
Save, refresh the mind map page, sidebar should populate.
SillyTavern crashes on startup with cannot find module 'express'
Symptom: ST refuses to start; the terminal log shows Error: Cannot find module 'express' with a stack trace pointing at the chronicle-db plugin.
Cause: Older release tarballs (v0.1.x) didn't list express in the server-plugin's package.json — it was relying on a top-level npm install at the repo root that you may have skipped if you cloned the plugin folder by hand.
Fix: Either pull the latest master (where express is now declared), or just install it directly into the plugin folder:
cd <wherever you cloned chronicledb>/server-plugin
npm install express
Then restart ST.
Status badge stays red — getaddrinfo ENOTFOUND in the log
Symptom: Status badge is red, and the ST terminal log shows getaddrinfo ENOTFOUND db.something.supabase.co (or similar) on each connect attempt.
Cause: The hostname in the Database panel doesn't resolve via DNS. The most common reasons: a typo, a leading/trailing space (yes, really), or you pasted the placeholder from the Supabase docs (db.[YOUR-REF].supabase.co) without substituting your actual project ref.
Fix: Open the Database section, double-check the host field. For Supabase, it should be db.<your-12-char-project-ref>.supabase.co — no [, ], or trailing whitespace. Save and the plugin retries automatically.
Status badge stays red — Supabase connects but schema init fails
Symptom: The plugin reaches Supabase but Connect & initialize errors out, often with a complaint about CREATE EXTENSION or DDL inside a transaction.
Cause: Two possibilities, both Supabase-specific.
- Wrong port. 6543 is the transaction pooler — pgvector + the schema-init transactions don't survive PgBouncer's transaction mode. Use 5432 (the direct connection) instead.
- Extensions not enabled. Supabase doesn't enable
vectorandpg_trgmby default. Open Database → Extensions in the Supabase dashboard and toggle both on.
PowerShell refuses to create the symlinks (Windows manual install)
Symptom: New-Item -ItemType SymbolicLink errors out with "A required privilege is not held by the client" or similar.
Fix: Don't use SymbolicLink — use a Junction instead. Junctions are NTFS reparse points for directories that don't require admin or Developer Mode:
New-Item -ItemType Junction `
-Path $HOME\SillyTavern\plugins\chronicle-db `
-Target <path-to-chronicledb>\server-plugin
Or just run install.ps1 — it uses junctions out of the box, no manual steps needed.
Mind map nodes are present but no memory ever appears in chat context
Symptom: Extraction is clearly happening (you can see characters and events in the mind map), but ST's chat completion log shows no [ChronicleDB Memory] block being injected.
First check: the Enable ChronicleDB toggle at the top of the settings panel is on. If yes, open Debug: recent LLM calls at the bottom and confirm the memory model is being called — if it's silent during a fresh reply, the inject hook isn't firing. Restart ST once; if still silent, file an issue with the contents of the debug table.
Same character appears as multiple nodes in the mind map
Symptom: "James Roe" and "Captain Roe" (or "Lyra" / "Lady Lyra" / "the merchant's daughter" etc.) show up as separate nodes even though they're the same person in your story.
Cause: Pre-master extractor only deduped on exact name match. Newer builds (post the alias-aware upsertCharacter fix) collapse surface variants automatically going forward, but pre-existing duplicates need a one-shot merge.
Fix: Pull master and run server-plugin/merge-characters.js from the repo root. Pass --canonical "Real Name" and --merge "Variant 1" "Variant 2" .... Add --dry-run first to preview. Stop ST first if you're on PGlite (single-writer lock).
Hit something not covered here? Open an issue at github.com/alani-fan-club/chronicledb/issues with the contents of the ST terminal log around the failure — that's almost always enough to diagnose.