diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 4dd0be89..fb00c4ef 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,12 +1,12 @@ { "name": "scribe-plugin", "owner": { "name": "Bryan Van Deusen" }, - "description": "Scribe ships its own Claude Code plugin from this repo, versioned in lockstep with the app + the /api/plugin/context contract.", + "description": "Grimoire ships its own Claude Code plugin from this repo, versioned in lockstep with the app + the /api/plugin/context contract.", "plugins": [ { "name": "scribe", "source": "./plugin", - "description": "Scribe second brain: MCP tools + session-start push channel + universal process-skills." + "description": "Grimoire second brain: MCP tools + session-start push channel + universal process-skills." } ] } diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 807f8fb4..9609e3ff 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -99,7 +99,7 @@ jobs: # version check diffs two trees, so a depth-1 fetch of main is enough. - uses: actions/checkout@v6 - # Per-job rather than in the image: Scribe is shellcheck's only consumer. + # Per-job rather than in the image: Grimoire is shellcheck's only consumer. # Install nothing else here; the hooks use only POSIX tools, and the # smoke test runs on a bare image to prove it. - name: Install shell tooling diff --git a/README.md b/README.md index 1050f18c..ae5c924e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Fabled Scribe +# Fabled Grimoire A self-hosted work system-of-record for software projects, built to be driven by Claude Code. Notes, tasks, issues, projects, milestones, rules, and stored processes — reachable from Claude via a built-in MCP endpoint and a bundled Claude Code plugin, with a clean web UI for humans. No in-app LLM; Claude is the sole assistant. @@ -34,7 +34,7 @@ Open `http://localhost:5000`. The first user to register becomes admin. To conne | [API Keys & MCP](docs/api-keys-and-mcp.md) | API keys and installing the Claude Code plugin | | [SSO / OAuth](docs/sso-oauth.md) | OIDC setup for Authentik, Keycloak, and other providers | | [Backups](docs/backups.md) | Scheduled backups to a folder or S3, and restoring from one | -| [Design system](docs/design-system.md) | The FabledSword house style and how Scribe applies it | +| [Design system](docs/design-system.md) | The FabledSword house style and how Grimoire applies it | | [API Reference](docs/api-reference.md) | All REST API endpoints | ## License diff --git a/ci-requirements.md b/ci-requirements.md index 830dae4f..a91169c7 100644 --- a/ci-requirements.md +++ b/ci-requirements.md @@ -29,7 +29,7 @@ Anything CI installs at job time that isn't in the image. Promotion candidates if more than one project needs them. - `shellcheck` — apt-installed in the **plugin** job, which lints the - Claude Code hook scripts and runs their fail-open smoke test. Scribe is + Claude Code hook scripts and runs their fail-open smoke test. Grimoire is its only consumer, so per `docs/process.md` it stays per-job. It is small (~20 MB) and a promotion candidate once another project lints shell. diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 578c4564..c821b44e 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -11,7 +11,7 @@ services: - scribe_backend db: - # Postgres 17 with the vector extension Scribe needs. + # Postgres 17 with the vector extension Grimoire needs. image: pgvector/pgvector:pg17 stop_grace_period: 120s volumes: diff --git a/docker-compose.quickstart.yml b/docker-compose.quickstart.yml index 05a8bbe1..62133c39 100644 --- a/docker-compose.quickstart.yml +++ b/docker-compose.quickstart.yml @@ -1,4 +1,4 @@ -# Fabled Scribe from the pre-built image: +# Fabled Grimoire from the pre-built image: # docker compose -f docker-compose.quickstart.yml up -d # Then open http://localhost:5000 (the first account registered becomes admin) # and connect Claude from Settings → MCP Access. @@ -20,7 +20,7 @@ services: restart: unless-stopped db: - # Postgres 17 with the vector extension Scribe needs. + # Postgres 17 with the vector extension Grimoire needs. image: pgvector/pgvector:pg17 stop_grace_period: 120s volumes: diff --git a/docker-compose.yml b/docker-compose.yml index 6da3ce1a..3aed715a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,7 +17,7 @@ services: # SEARXNG_URL: "http://searxng:8080" db: - # Postgres 17 with the vector extension Scribe needs. + # Postgres 17 with the vector extension Grimoire needs. image: pgvector/pgvector:pg17 stop_grace_period: 120s restart: unless-stopped diff --git a/docs/api-keys-and-mcp.md b/docs/api-keys-and-mcp.md index e260d0fc..77815ed6 100644 --- a/docs/api-keys-and-mcp.md +++ b/docs/api-keys-and-mcp.md @@ -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 ` 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 diff --git a/docs/api-reference.md b/docs/api-reference.md index 14e2b47d..c815b8aa 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -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 diff --git a/docs/architecture.md b/docs/architecture.md index 71718522..886a5098 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -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 diff --git a/docs/backups.md b/docs/backups.md index 2fe45b6b..9a4e00d2 100644 --- a/docs/backups.md +++ b/docs/backups.md @@ -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 `.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://: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 diff --git a/docs/configuration.md b/docs/configuration.md index 88dc65c4..56461714 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -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 `_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 `_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. diff --git a/docs/design-system.md b/docs/design-system.md index d22ed87e..2c9b575b 100644 --- a/docs/design-system.md +++ b/docs/design-system.md @@ -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. diff --git a/docs/development.md b/docs/development.md index fd11a0a1..1a925a8f 100644 --- a/docs/development.md +++ b/docs/development.md @@ -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 diff --git a/docs/features.md b/docs/features.md index 3fcaa272..1180b8dd 100644 --- a/docs/features.md +++ b/docs/features.md @@ -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). diff --git a/docs/sso-oauth.md b/docs/sso-oauth.md index ee336a9e..f1a4965e 100644 --- a/docs/sso-oauth.md +++ b/docs/sso-oauth.md @@ -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 (`/.well-known/openid-configuration`) must be publicly reachable from the Scribe container (server-to-server call at login time). +The OIDC discovery endpoint (`/.well-known/openid-configuration`) must be publicly reachable from the Grimoire container (server-to-server call at login time). diff --git a/frontend/index.html b/frontend/index.html index 6fdfe7a6..56a29eb4 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -9,8 +9,8 @@ - - Fabled Scribe + + Fabled Grimoire
diff --git a/frontend/public/manifest.json b/frontend/public/manifest.json index d3748688..0f869653 100644 --- a/frontend/public/manifest.json +++ b/frontend/public/manifest.json @@ -1,6 +1,6 @@ { - "name": "Fabled Scribe", - "short_name": "Scribe", + "name": "Fabled Grimoire", + "short_name": "Grimoire", "description": "Your self-hosted second brain with AI assistance", "start_url": "/", "display": "standalone", diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 145364be..cd1a2d1b 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -68,7 +68,7 @@ export function apiErrorMessage(e: unknown, fallback: string): string { */ const DEFAULT_TIMEOUT_MS = 30_000; -/** HTTP 408. Not a status any Scribe route returns, so it unambiguously means +/** HTTP 408. Not a status any Grimoire route returns, so it unambiguously means * "the client gave up" rather than anything the server said. */ const CLIENT_TIMEOUT_STATUS = 408; diff --git a/frontend/src/api/replyShapes.ts b/frontend/src/api/replyShapes.ts index cd877eb2..8092877e 100644 --- a/frontend/src/api/replyShapes.ts +++ b/frontend/src/api/replyShapes.ts @@ -1,7 +1,7 @@ import { apiGet } from "@/api/client"; /** - * The reply shapes Scribe ships — `GET /api/retrieval/reply-shapes`. + * The reply shapes Grimoire ships — `GET /api/retrieval/reply-shapes`. * The same catalog the `list_reply_shapes` MCP tool returns, plus what only * the operator's view needs: the preferences mounted on each shape's moment, * and how often each shape was delivered. diff --git a/frontend/src/api/snippets.ts b/frontend/src/api/snippets.ts index 6545b09e..ae8a221e 100644 --- a/frontend/src/api/snippets.ts +++ b/frontend/src/api/snippets.ts @@ -62,7 +62,7 @@ export interface Snippet { export type SnippetUsage = RecordUsage; /** Result of the last drift check — does the recorded location and code still - * match source? The check runs agent-side (Scribe has no checkout); this is the + * match source? The check runs agent-side (Grimoire has no checkout); this is the * remembered verdict. `current` is false once the snippet has been edited since * the check, at which point the verdict describes code that's no longer there. */ export interface SnippetVerification { @@ -188,7 +188,7 @@ export async function findDuplicateSnippets( } /** Record a drift-check verdict. The check itself runs where the code is — an - * agent with the working tree — since Scribe has no checkout. This stores what + * agent with the working tree — since Grimoire has no checkout. This stores what * was found, and is how the UI clears a stale marker after a manual fix. */ export async function verifySnippet( id: number, diff --git a/frontend/src/assets/theme.css b/frontend/src/assets/theme.css index 9fa9ad2b..13b1c799 100644 --- a/frontend/src/assets/theme.css +++ b/frontend/src/assets/theme.css @@ -1,7 +1,7 @@ @import url('https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300..900;1,9..144,300..900&family=Inter:ital,wght@0,400;0,500;1,400&family=JetBrains+Mono:ital,wght@0,400;1,400&display=swap'); /* ========================================================================== - GENERATED FROM THE DESIGN SYSTEM — Scribe (design system 2), which inherits + GENERATED FROM THE DESIGN SYSTEM — Grimoire (design system 2), which inherits the FabledSword house style (design system 1). Do not hand-edit the --fs-* block below. Edit the design system in the app @@ -26,7 +26,7 @@ :root { /* accent */ - --fs-accent: #5B4A8A; /* Scribe's signature colour */ + --fs-accent: #5B4A8A; /* Grimoire's signature colour */ --fs-accent-soft: color-mix(in srgb, var(--fs-accent) 15%, transparent); /* Pill, tag and badge backgrounds */ --fs-accent-faint: color-mix(in srgb, var(--fs-accent) 8%, transparent); /* The faintest accent wash */ --fs-accent-deep: color-mix(in srgb, var(--fs-accent) 70%, black); /* The accent, darkened */ diff --git a/frontend/src/components/AppHeader.vue b/frontend/src/components/AppHeader.vue index 1f5fbb7c..737dff1c 100644 --- a/frontend/src/components/AppHeader.vue +++ b/frontend/src/components/AppHeader.vue @@ -39,7 +39,7 @@ router.afterEach(() => { - Scribe + Grimoire diff --git a/frontend/src/components/BackupScheduleSettings.vue b/frontend/src/components/BackupScheduleSettings.vue index bfca1fb1..f93870c2 100644 --- a/frontend/src/components/BackupScheduleSettings.vue +++ b/frontend/src/components/BackupScheduleSettings.vue @@ -189,7 +189,7 @@ async function backUpNow() {

Each run adds one dated file, scribe-<date>.tar, holding every table as plain lines. It is not compressed, so a deduplicating tool such as restic stores only what - changed since the day before. Scribe never deletes old backups — the destination keeps and + changed since the day before. Grimoire never deletes old backups — the destination keeps and thins the history. Sharing, API keys and forge connections are not included.

@@ -223,7 +223,7 @@ async function backUpNow() { Folder - A path inside the Scribe container — usually a share mounted there that a backup + A path inside the Grimoire container — usually a share mounted there that a backup service watches. diff --git a/frontend/src/components/MomentsSettings.vue b/frontend/src/components/MomentsSettings.vue index 5b898dd1..bff473f7 100644 --- a/frontend/src/components/MomentsSettings.vue +++ b/frontend/src/components/MomentsSettings.vue @@ -153,7 +153,7 @@ onMounted(() => store.load(true)); v-for="a in actionsFor(m.name)" :key="`${a.via}:${a.tool}:${a.match}`" :class="['action-chip', { 'is-install': a.via === 'install' }]" - :title="a.via === 'install' ? 'Added on this install' : 'Ships with Scribe'" + :title="a.via === 'install' ? 'Added on this install' : 'Ships with Grimoire'" > {{ actionLabel(a) }}
-

Ships with Scribe · at {{ s.moment }}

+

Ships with Grimoire · at {{ s.moment }}

{{ s.text }}

Your adjustments

diff --git a/frontend/src/components/rules/PreferenceDriftPane.vue b/frontend/src/components/rules/PreferenceDriftPane.vue index 2946120a..6ca89b4b 100644 --- a/frontend/src/components/rules/PreferenceDriftPane.vue +++ b/frontend/src/components/rules/PreferenceDriftPane.vue @@ -1,6 +1,6 @@