rename(547): what people read says Grimoire
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / integration (push) Successful in 1m1s
CI & Build / Python tests (push) Successful in 1m55s
CI & Build / Build & push image (push) Successful in 36s

Step 1 of the Scribe -> Grimoire rename: every capitalised "Scribe" in prose
becomes "Grimoire" ("Fabled Scribe" -> "Fabled Grimoire") across the UI,
the PWA manifest and page title, the MCP instructions and tool docstrings,
hook and skill text, docs and README, with the tests that assert on that
prose moving with it. Old migrations keep their wording.

Identifiers are untouched here: the package, plugin name, MCP server key,
hook file names, env vars, the .scribe marker and FabledScribe repo/image
names move in steps 2 and 3, along with prose that quotes them.

The sweep matched "Scribe" only as a whole word, so describe/subscribe and
friends are untouched. The longer name took the MCP instructions one
character over their 1,600 budget; two phrases are shortened to fit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-22 10:46:37 -04:00
co-authored by Claude Opus 5.5
parent 06be537a18
commit e99f1169f7
142 changed files with 460 additions and 460 deletions
+8 -8
View File
@@ -1,8 +1,8 @@
# API Keys and Scribe MCP
# API Keys and Grimoire MCP
## API Keys
API keys let external tools access your Scribe data without a browser session. Each key is scoped to a single user — it can only access data that user owns or has been shared with them.
API keys let external tools access your Grimoire data without a browser session. Each key is scoped to a single user — it can only access data that user owns or has been shared with them.
### Scopes
@@ -22,7 +22,7 @@ Admin-level operations (log access, user management) require a `write`-scoped ke
5. Copy the key immediately — it is shown only once (the token is `fmcp_`-prefixed)
Paste the key into the `Authorization: Bearer <key>` header of your MCP client
config (see **Scribe MCP Server** below).
config (see **Grimoire MCP Server** below).
### Revoking a Key
@@ -30,12 +30,12 @@ Click **Revoke** next to the key in the keys table and confirm. Revoked keys are
---
## Scribe MCP Server
## Grimoire MCP Server
Scribe exposes itself as a set of MCP tools that Claude (and other MCP clients)
Grimoire exposes itself as a set of MCP tools that Claude (and other MCP clients)
can use to read and write your notes, tasks, projects, rulebooks, and more. The
server is **built into the app** — it is mounted as a streamable-HTTP endpoint
at **`/mcp`** on the running Scribe instance (`src/scribe/mcp/server.py`). There
at **`/mcp`** on the running Grimoire instance (`src/scribe/mcp/server.py`). There
is nothing to install: no wheel, no separate package, no CLI. You connect a
client straight to the URL with a Bearer token.
@@ -50,14 +50,14 @@ without a read-shaped name are spelled out here. A `write`-scoped key may call e
### Claude Code: the plugin (recommended)
The plugin connects the MCP server and adds the hooks and skills that put Scribe's records in front of Claude as it works. Install it from this repo:
The plugin connects the MCP server and adds the hooks and skills that put Grimoire's records in front of Claude as it works. Install it from this repo:
```
/plugin marketplace add https://git.fabledsword.com/bvandeusen/FabledScribe.git
/plugin install scribe@scribe-plugin
```
It asks for your Scribe base URL, an API key (kept in your OS keychain) and, optionally, a project id. Settings → MCP Access shows the exact command for your instance. [`plugin/README.md`](../plugin/README.md) describes each hook.
It asks for your Grimoire base URL, an API key (kept in your OS keychain) and, optionally, a project id. Settings → MCP Access shows the exact command for your instance. [`plugin/README.md`](../plugin/README.md) describes each hook.
### Claude Code without the plugin
+1 -1
View File
@@ -291,7 +291,7 @@ These serve the plugin's hooks.
|--------|------|-------------|
| POST | `/api/webhooks/forge` | Push events from a git forge, verified with `FORGE_WEBHOOK_SECRET` **(public)** |
## Scribe MCP
## Grimoire MCP
Claude clients connect to the built-in MCP server at `POST /mcp` (streamable HTTP,
Bearer auth with an `fmcp_` key), served by `src/scribe/mcp/`. It is not a REST
+2 -2
View File
@@ -1,6 +1,6 @@
# Architecture
Scribe is one app container and one PostgreSQL container. There is no language model in the stack: Claude works with Scribe from outside, through the MCP endpoint and the Claude Code plugin, and people use the web UI.
Grimoire is one app container and one PostgreSQL container. There is no language model in the stack: Claude works with Grimoire from outside, through the MCP endpoint and the Claude Code plugin, and people use the web UI.
## Stack
@@ -74,7 +74,7 @@ Every database wait on startup has a deadline. Migrations wait for the database
- **OIDC** single sign-on with PKCE, optionally replacing local logins ([SSO / OAuth](sso-oauth.md)).
- **Rate limits** on register, login and forgot-password, per client IP (`TRUST_PROXY_HEADERS` reads the IP from the proxy's headers).
Credentials Scribe stores for outside services (forge tokens, the backup destination's S3 secret) are sealed under a key derived from `SECRET_KEY`.
Credentials Grimoire stores for outside services (forge tokens, the backup destination's S3 secret) are sealed under a key derived from `SECRET_KEY`.
## Repository layout
+17 -17
View File
@@ -1,7 +1,7 @@
# Backups
Scribe can back itself up every day to a **folder** or an **S3-compatible
bucket**. Each run adds one file; Scribe never deletes an old one. Keeping and
Grimoire can back itself up every day to a **folder** or an **S3-compatible
bucket**. Each run adds one file; Grimoire never deletes an old one. Keeping and
thinning the history is the destination's job.
Set it up under **Settings → Data → Scheduled backups** (admins only).
@@ -16,14 +16,14 @@ scribe-20261015T020000Z.tar
It is a plain, **uncompressed** tar:
- `manifest.json` comes first. It holds the backup format version, the Scribe
- `manifest.json` comes first. It holds the backup format version, the Grimoire
version, when the backup was taken, and how many rows each table has.
- Then there is one `<table>.jsonl` per table, one row per line.
It holds everything the admin **Full Backup** download holds, laid out
differently. It does **not** hold:
- **Search indexes.** They are rebuilt from the records when Scribe starts.
- **Search indexes.** They are rebuilt from the records when Grimoire starts.
- **Sharing:** groups, project shares and note shares.
- **Credentials:** API keys and forge connections. After a restore, issue new
API keys and add forge connections again. (Forge tokens are also sealed under
@@ -61,7 +61,7 @@ file again.
### A folder
A path **inside the Scribe container**, normally a share mounted there:
A path **inside the Grimoire container**, normally a share mounted there:
```yaml
services:
@@ -70,7 +70,7 @@ services:
- /nfs/backup/scribe:/backups
```
Scribe writes each file under a hidden name (`.scribe-….tar.part`) and renames
Grimoire writes each file under a hidden name (`.scribe-….tar.part`) and renames
it once it is complete. A program watching the folder never sees half a
backup.
@@ -79,12 +79,12 @@ backup.
You need four things:
- **Address:** the service itself, like `https://backup.example.com`. Don't
include the bucket; Scribe addresses buckets by path.
include the bucket; Grimoire addresses buckets by path.
- **Bucket.**
- **Access key.**
- **Secret key.**
Scribe uploads and lists; it never deletes. A key that may **only add
Grimoire uploads and lists; it never deletes. A key that may **only add
objects** is therefore enough, and it is the safer key to hand out: a stolen
one cannot wipe the history.
@@ -115,21 +115,21 @@ page asks for the secret again.
[Fabled Archives](https://git.fabledsword.com/bvandeusen/fabledarchives)
keeps service backups as "backup targets". Either destination works with it.
1. On Archives' **Backups** page, make a target for Scribe, named `scribe`
1. On Archives' **Backups** page, make a target for Grimoire, named `scribe`
for example.
2. Choose how Scribe's files arrive:
2. Choose how Grimoire's files arrive:
- **S3**: turn on the S3 way in for the target and make an **append-only**
S3 key. In Scribe, choose **An S3 bucket**:
S3 key. In Grimoire, choose **An S3 bucket**:
- address: Archives' backup address (`http://<archives>:8081`);
- bucket: the target's name;
- access key and secret key: the key you just made.
- **A folder**: mount the share Archives watches into Scribe as
`/backups/scribe`, and point the target at that folder. In Scribe, choose
- **A folder**: mount the share Archives watches into Grimoire as
`/backups/scribe`, and point the target at that folder. In Grimoire, choose
**A folder** with `/backups/scribe`.
3. Set the target's **Retention** to **Archives**. Archives then keeps the
newest backups and thins the rest by day, week and month. Scribe only adds.
newest backups and thins the rest by day, week and month. Grimoire only adds.
4. Give the target an expected cadence of **daily**, so a missed backup turns
it late in Archives as well as overdue in Scribe.
it late in Archives as well as overdue in Grimoire.
5. Add an off-site **restic** replication job for the target. The uncompressed
layout above is what lets that job send only what changed each day.
@@ -137,7 +137,7 @@ keeps service backups as "backup targets". Either destination works with it.
### Into a fresh instance
Start Scribe on an empty database, copy the backup file into the container,
Start Grimoire on an empty database, copy the backup file into the container,
and run:
```sh
@@ -150,7 +150,7 @@ docker exec -it scribe python -m scribe.restore /backups/scribe-20261015T020000Z
- Nothing limits the file's size.
- It also reads the JSON from the admin **Full Backup** download.
Afterwards, **restart Scribe** so the search indexes are rebuilt. Then issue
Afterwards, **restart Grimoire** so the search indexes are rebuilt. Then issue
new API keys, add forge connections again, and set up any sharing.
### From the web
+6 -6
View File
@@ -1,6 +1,6 @@
# Configuration
Scribe reads its configuration from environment variables. Most settings people change day to day (registration, SMTP, retrieval thresholds, backups, forge connections) live in **Settings** in the web UI instead.
Grimoire reads its configuration from environment variables. Most settings people change day to day (registration, SMTP, retrieval thresholds, backups, forge connections) live in **Settings** in the web UI instead.
Any variable marked *secret* can also be read from a file: set `<NAME>_FILE` to the path, for example a Docker secret at `/run/secrets/scribe_key`.
@@ -13,7 +13,7 @@ Any variable marked *secret* can also be read from a file: set `<NAME>_FILE` to
| `DATABASE_URL` *(secret)* | `postgresql+asyncpg://scribe:scribe@localhost:5432/scribe` | PostgreSQL connection string, using the `asyncpg` driver |
| `SECRET_KEY` *(secret)* | `dev-secret-change-me` | Signs sessions and seals stored credentials. Set it before first use and keep it (see below) |
| `BASE_URL` | `http://localhost:5000` | Public URL, used in email links and OIDC redirects |
| `SECURE_COOKIES` | `false` | `true` when Scribe is served over HTTPS |
| `SECURE_COOKIES` | `false` | `true` when Grimoire is served over HTTPS |
| `TRUST_PROXY_HEADERS` | `false` | `true` behind a reverse proxy, to read the client IP from `X-Forwarded-For` / `X-Real-IP` |
| `LOG_LEVEL` | `INFO` | `DEBUG`, `INFO`, `WARNING` or `ERROR` |
| `LOG_RETENTION_DAYS` | `90` | Days of app logs to keep |
@@ -42,7 +42,7 @@ Admins can set SMTP in **Settings**; these are the defaults until they do.
| `SMTP_USERNAME` | — |
| `SMTP_PASSWORD` *(secret)* | — |
| `SMTP_FROM_ADDRESS` | — |
| `SMTP_FROM_NAME` | `Fabled Scribe` |
| `SMTP_FROM_NAME` | `Fabled Grimoire` |
| `SMTP_USE_TLS` | `true` |
### Integrations
@@ -86,14 +86,14 @@ The shipped files leave out healthchecks and restart policies on purpose. The ap
### Volumes
- **Database** (`pgdata`): everything Scribe stores.
- **Database** (`pgdata`): everything Grimoire stores.
- **App data** (`/data`): the embedding model cache and diagnostics. Losing it costs a re-download, nothing else.
Back up the database with **Settings → Data → Scheduled backups** ([Backups](backups.md)).
## Behind a reverse proxy
Scribe doesn't terminate TLS. Put it behind Nginx, Traefik or Caddy, forward to port 5000, and keep port 5000 off the internet. Set `SECURE_COOKIES=true`, `TRUST_PROXY_HEADERS=true` and `BASE_URL`.
Grimoire doesn't terminate TLS. Put it behind Nginx, Traefik or Caddy, forward to port 5000, and keep port 5000 off the internet. Set `SECURE_COOKIES=true`, `TRUST_PROXY_HEADERS=true` and `BASE_URL`.
```nginx
location / {
@@ -114,7 +114,7 @@ With `TRUST_PROXY_HEADERS=true`, make sure the proxy replaces any `X-Forwarded-F
## Security checklist
- **Set a strong `SECRET_KEY`, and keep it.** Forge tokens and the backup destination's S3 secret are sealed under a key derived from it, so a copy of the database alone can't read them. If the key changes (say, a restore onto an instance with a different key), Settings marks those credentials and asks for them again; nothing else breaks. The app logs a warning at startup while the default key is in use, and refuses to start with it when `SECURE_COOKIES=true`.
- **`SECURE_COOKIES=true`** whenever Scribe is served over HTTPS.
- **`SECURE_COOKIES=true`** whenever Grimoire is served over HTTPS.
- **Registration** is open only for the first account. Invite people, or open it briefly from Settings.
- **Signing everyone else out**: changing a password ends that user's other sessions; Settings → Account has a button for it too.
- **API keys** are per user, shown once, and can be read-only. Revoke any you no longer use under Settings → MCP Access.
+10 -10
View File
@@ -53,7 +53,7 @@ Parchment is intentionally not pure white — it's slightly warm to feel like ag
| Bronze | `#8B7355` | Secondary action buttons (Cancel-but-not-destructive, alternate paths) |
| Pewter | `#3F4651` | Tertiary/ghost buttons |
**Critical rule:** Action button colors are universal across all apps. A Save button in Scribe and a Save button in Minstrel look identical. Per-app accents do not appear on buttons.
**Critical rule:** Action button colors are universal across all apps. A Save button in Grimoire and a Save button in Minstrel look identical. Per-app accents do not appear on buttons.
### Semantic colors
@@ -71,7 +71,7 @@ Parchment is intentionally not pure white — it's slightly warm to feel like ag
| App | Hex | Mood |
|---|---|---|
| Fabled Scribe | `#5B4A8A` | Dusty violet — ink, manuscripts |
| Fabled Grimoire | `#5B4A8A` | Dusty violet — ink, manuscripts |
| Minstrel | `#4A6B5C` | Forest teal — music, performance |
| Fabled Forge | `#8B5A2B` | Forge bronze — creation, craft |
| Roundtable | `#4A5D7E` | Slate blue — stewardship, infrastructure |
@@ -80,7 +80,7 @@ Parchment is intentionally not pure white — it's slightly warm to feel like ag
**Accent usage rules:**
- The accent appears on the app's wordmark and icon.
- The accent indicates active/current state in nav (the selected page, the active tab).
- The accent is the cursor color and text-selection color in long-form surfaces (Scribe notes, Forge story drafts).
- The accent is the cursor color and text-selection color in long-form surfaces (Grimoire notes, Forge story drafts).
- The accent does NOT appear on primary or secondary action buttons.
- The accent does NOT appear in body text or chrome.
- One accent per app. Don't mix accents within a single app.
@@ -124,7 +124,7 @@ Fraunces is a contemporary serif with personality — it has the warmth and auth
- **Sentence case everywhere.** Never Title Case for headings, never ALL CAPS except for the Tiny micro-label style.
- **Two weights only:** 400 regular and 500 medium. Never 600 or 700 — they read heavy in dark mode.
- **Fraunces only at 18px and above.** Below that it loses too much detail and feels fragile. For h3 and below, use Inter.
- **Line height** 1.5 for body, 1.3 for headings, 1.7 for long-form reading surfaces (Scribe notes, Forge drafts).
- **Line height** 1.5 for body, 1.3 for headings, 1.7 for long-form reading surfaces (Grimoire notes, Forge drafts).
- **Letter-spacing** at default for everything except the Tiny micro-label, which gets `0.08em` letter-spacing and uppercase styling.
---
@@ -173,7 +173,7 @@ Padding: `8px 16px` for default, `6px 12px` for compact, `10px 20px` for promine
Used for tags, hashtags, code spans, status badges. Background is the accent color at ~15% opacity, text is the accent at full strength. Border-radius 4px, padding `2px 8px`, Inter 11px/500.
In Scribe specifically, hashtags and tags use the dusty violet accent. In Minstrel, they'd use forest teal. The pattern is shared; the color follows the app.
In Grimoire specifically, hashtags and tags use the dusty violet accent. In Minstrel, they'd use forest teal. The pattern is shared; the color follows the app.
### Cards
@@ -272,9 +272,9 @@ Use **Lucide** (https://lucide.dev) as the base icon set — it matches this sty
## Per-app application
### Fabled Scribe (#5B4A8A — dusty violet)
### Fabled Grimoire (#5B4A8A — dusty violet)
A second-brain notes and task management tool. The accent appears in: the wordmark, hashtags and tag pills, the active nav item, text selection color, and the cursor in the editor. Notes are presented on Iron-surfaced cards with generous reading line-height. The hashtag system uses Scribe's accent for visual continuity.
A second-brain notes and task management tool. The accent appears in: the wordmark, hashtags and tag pills, the active nav item, text selection color, and the cursor in the editor. Notes are presented on Iron-surfaced cards with generous reading line-height. The hashtag system uses Grimoire's accent for visual continuity.
### Minstrel (#4A6B5C — forest teal)
@@ -354,11 +354,11 @@ If using Tailwind, extend the theme with these tokens rather than relying on def
---
# Scribe
# Grimoire
The design system Scribe renders with is stored in Scribe itself: **Scribe**, which inherits **FabledSword**, edited at `/design-systems`. `frontend/src/assets/theme.css` is generated from it, and CI rejects a `var()` the sheet doesn't define. Where this page and the stored system differ, the stored system is right. Scribe applies the baseline above with these choices:
The design system Grimoire renders with is stored in Grimoire itself: **Grimoire**, which inherits **FabledSword**, edited at `/design-systems`. `frontend/src/assets/theme.css` is generated from it, and CI rejects a `var()` the sheet doesn't define. Where this page and the stored system differ, the stored system is right. Grimoire applies the baseline above with these choices:
- **Accent footprint.** Dusty violet marks Scribe's own moments: the wordmark, active navigation, the editor's cursor and selection, tags and wikilinks, in-progress status, focus rings, and the call to action that starts something new (a first note, say). Operating the software uses the action colours: Moss to save or confirm, Bronze for alternatives, Oxblood with an icon to delete, Pewter ghost for tertiary actions.
- **Accent footprint.** Dusty violet marks Grimoire's own moments: the wordmark, active navigation, the editor's cursor and selection, tags and wikilinks, in-progress status, focus rings, and the call to action that starts something new (a first note, say). Operating the software uses the action colours: Moss to save or confirm, Bronze for alternatives, Oxblood with an icon to delete, Pewter ghost for tertiary actions.
- **Light and dark.** Both are supported. Light mode is warm parchment (`#F5F1E8` page, `#FBF8F0` cards, `#14171A` text) rather than white, with a cool wash on code blocks so syntax colours stay readable. The accent, action and semantic colours are the same in both.
- **Status and priority.** Status: todo Pewter, in progress the accent, done Moss, cancelled Ash, paused Warning. Priority runs cool to warm: low Info, medium Warning, high Error. Overdue uses Error. Each has a low-alpha `-bg` companion.
- **Type.** Inter for UI and body, Fraunces at 18px and up (display, H1, H2), JetBrains Mono for code. Two weights only, 400 and 500. Line height 1.5 for body, 1.3 for headings, 1.7 on reading surfaces such as a note.
+1 -1
View File
@@ -45,7 +45,7 @@ docker compose exec app alembic revision -m "short_description"
`plugin/` ships straight from git: installs fetch it through `.claude-plugin/marketplace.json`, and there is no build step. After changing anything under `plugin/` or `.claude-plugin/`, run `make mint-plugin` before committing. Claude Code only refreshes an installed plugin when its version changes, and CI fails a plugin change that didn't bump it.
The hooks must run on a bare machine: POSIX shell, awk, sed and the usual coreutils, plus `git` and `curl`. They fail open, so a slow or unreachable Scribe never blocks Claude Code.
The hooks must run on a bare machine: POSIX shell, awk, sed and the usual coreutils, plus `git` and `curl`. They fail open, so a slow or unreachable Grimoire never blocks Claude Code.
## CI and releases
+6 -6
View File
@@ -1,6 +1,6 @@
# Features
Scribe is a self-hosted system of record for the work you do with Claude Code. Claude records what it learned, decided and built, and that record reaches the next session, so a solution is recalled rather than reinvented. There is no language model inside Scribe: Claude reaches it through the MCP endpoint and the Claude Code plugin, and the web UI is where people read and edit the same records.
Grimoire is a self-hosted system of record for the work you do with Claude Code. Claude records what it learned, decided and built, and that record reaches the next session, so a solution is recalled rather than reinvented. There is no language model inside Grimoire: Claude reaches it through the MCP endpoint and the Claude Code plugin, and the web UI is where people read and edit the same records.
## Notes
@@ -40,8 +40,8 @@ A task is a note with a status (`todo`, `in_progress`, `done`, `cancelled`), plu
## Snippets and the shape ledger
- **Snippets** are recorded prior art: a reusable piece of code with when to reach for it, its signature and its canonical location in a repo. Claude searches them before building and is shown matching ones before it writes a file.
- **Forge integration**: with a git forge connected, Scribe checks a snippet's cached body against its source and marks it current or diverged. Push webhooks keep that fresh.
- **The shape ledger**: Scribe extracts the code shapes from a bound repo and tracks how each is accounted for: an instance of a snippet, a deliberate variant with its reason, or a one-off. Coverage shows what is still unclassified.
- **Forge integration**: with a git forge connected, Grimoire checks a snippet's cached body against its source and marks it current or diverged. Push webhooks keep that fresh.
- **The shape ledger**: Grimoire extracts the code shapes from a bound repo and tracks how each is accounted for: an instance of a snippet, a deliberate variant with its reason, or a one-off. Coverage shows what is still unclassified.
## Family canon
@@ -49,7 +49,7 @@ Projects on the same platform (Android apps, Go services, ...) share good ideas.
## Design systems
Tokens (colour, type, space, motion, ...) and written guidance, with inheritance: a project's design system can extend a house style and record where it departs. Scribe generates a stylesheet from it, checks code snippets against it, and gives Claude the values to use before it writes UI. `/design-systems` edits them.
Tokens (colour, type, space, motion, ...) and written guidance, with inheritance: a project's design system can extend a house style and record where it departs. Grimoire generates a stylesheet from it, checks code snippets against it, and gives Claude the values to use before it writes UI. `/design-systems` edits them.
## Stored processes
@@ -65,8 +65,8 @@ Saved procedures, such as a drift audit or a DRY pass. The plugin syncs each one
The whole store is reachable through the MCP endpoint at `/mcp`, authenticated with an API key. The Claude Code plugin in this repo adds:
- hooks for session start, each prompt, before and after tool calls, the end of a turn, compaction and session end, all failing open if Scribe is unreachable;
- skills for the working practices: using Scribe, writing plans, systematic debugging, verification, brainstorming, reporting back, reusing code, shape accounting and family canon;
- hooks for session start, each prompt, before and after tool calls, the end of a turn, compaction and session end, all failing open if Grimoire is unreachable;
- skills for the working practices: using Grimoire, writing plans, systematic debugging, verification, brainstorming, reporting back, reusing code, shape accounting and family canon;
- your stored processes as skills.
See [API Keys & MCP](api-keys-and-mcp.md).
+5 -5
View File
@@ -1,6 +1,6 @@
# OAuth / OIDC SSO Setup
Scribe supports single sign-on via any OpenID Connect provider.
Grimoire supports single sign-on via any OpenID Connect provider.
This guide covers Authentik, but the same pattern works with Keycloak, Authelia, Zitadel, etc.
## 1. Create the provider in Authentik
@@ -8,7 +8,7 @@ This guide covers Authentik, but the same pattern works with Keycloak, Authelia,
1. Log in to the Authentik admin UI.
2. Go to **Applications → Providers → Create → OAuth2/OpenID Provider**.
3. Fill in:
- **Name:** `Scribe` (or whatever you like)
- **Name:** `Grimoire` (or whatever you like)
- **Authorization flow:** your default authorization flow
- **Client type:** `Confidential`
- **Redirect URIs:** `https://your-fabled-domain/api/auth/oauth/callback`
@@ -20,7 +20,7 @@ This guide covers Authentik, but the same pattern works with Keycloak, Authelia,
https://auth.example.com/application/o/fabled-assistant/
```
## 2. Configure Scribe
## 2. Configure Grimoire
Add the following environment variables to the `app` service in `docker-compose.yml`:
@@ -64,7 +64,7 @@ docker compose up --build -d
## 4. Account Linking
When a user logs in via OAuth for the first time, Scribe checks in this order:
When a user logs in via OAuth for the first time, Grimoire checks in this order:
1. **Existing OAuth sub** — returns that user immediately.
2. **Matching email** — if a local account already exists with the same email, the OAuth identity is linked to it automatically. The user retains all their notes and tasks.
@@ -92,4 +92,4 @@ The backend will reject any `POST /api/auth/login` or `POST /api/auth/register`
| Zitadel | `https://your-instance.zitadel.cloud` |
| Google | `https://accounts.google.com` |
The OIDC discovery endpoint (`<issuer>/.well-known/openid-configuration`) must be publicly reachable from the Scribe container (server-to-server call at login time).
The OIDC discovery endpoint (`<issuer>/.well-known/openid-configuration`) must be publicly reachable from the Grimoire container (server-to-server call at login time).