bvandeusenandClaude Opus 5.5 c8ede427ca
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 13s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / integration (push) Successful in 1m7s
CI & Build / Python tests (push) Failing after 1m30s
CI & Build / Build & push image (push) Skipped
align(4909d): every rule arm that annotates reads one bar, kb_rule_threshold at 0.70
prompt_rule, pre_tool_rule and write_path_rule now share one settings key,
RULE_FLOOR_KEY = "kb_rule_threshold", default 0.70. The reply backstop keeps
its own 0.80, because there the floor is a stop bar. Moving the shared floor
through tune_retrieval or the Settings form records a tuning event on every
surface that reads it (set_dial, via retrieval_surfaces.sharing_floor), and
the result names the surfaces it carried as `moved_with`. Settings shows one
"Standing-rule confidence threshold" control where it showed three.

Operator ruling (2026-10-05): one shared bar for the rule arms, "especially
since we're only taking the first x number of them" -- the budget limits
what is shown; the bar only decides what is worth ranking. Kept a dial.

Why 0.70, from records read rather than percentiles:
- write_path_rule near-misses at 0.7199-0.72 were all false positives
  (rule 149 against a Lidarr comment, 157 against a retention Svelte file,
  121 against an Archives restore, 164 against a config test, 131 against a
  Go package), so the old 0.72 was not hiding real hits -- but the band does
  noise control on this arm, so dropping 0.02 costs little.
- prompt_rule: the operator set 0.70 by hand on 2026-09-18, after a 0.60
  experiment admitted junk and was reverted. 0.70 is the number with a human
  decision behind it.
- pre_tool_rule lines near 0.68 this session were mostly noise; rising to
  0.70 trims them, and the band still narrows what clears.

Retired keys: kb_promptrule_threshold, kb_toolrule_threshold and
kb_rulehint_threshold are no longer read. Rows an install stored under them
stay in the settings table, inert. On this instance the effective bars move
pre_tool_rule 0.68 -> 0.70, write_path_rule 0.72 -> 0.70, prompt_rule stays
0.70; record_release_defaults writes those per-surface release rows on boot,
so the telemetry shift has an event to explain it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 18:32:09 -04:00

Fabled Grimoire

A self-hosted system of record for the work you do with Claude Code.

Claude records what it learned, decided and built in Grimoire, and that record reaches the next session, so a solution is recalled instead of reinvented. Notes, tasks, plans, rules, lessons and reusable code live in one place. Claude reaches them through a built-in MCP endpoint and the bundled Claude Code plugin, and people read and edit the same records in the web UI. There is no language model inside Grimoire: Claude is the only assistant.

Deploy

You need Docker with Compose. Save this as docker-compose.yml (it is the docker-compose.yml in this repository), then run docker compose up -d beside it:

# Fabled Grimoire: the app and its database.
#   docker compose up -d
# Then open http://localhost:5000. The first account registered becomes admin.
#
# Keep both volumes. app_data holds the instance's own SECRET_KEY, which seals
# saved credentials; pgdata holds everything else.

services:
  app:
    image: git.fabledsword.com/bvandeusen/fabledgrimoire:latest
    ports:
      - "5000:5000"
    environment:
      DATABASE_URL: "postgresql+asyncpg://${POSTGRES_USER:-grimoire}:${POSTGRES_PASSWORD:-grimoire}@db:5432/${POSTGRES_DB:-grimoire}"
      LOG_LEVEL: "${LOG_LEVEL:-INFO}"
      # Behind an HTTPS reverse proxy:
      # BASE_URL: "https://grimoire.example.com"
      # SECURE_COOKIES: "true"
      # TRUST_PROXY_HEADERS: "true"
    volumes:
      - app_data:/data
    depends_on:
      - db
    restart: unless-stopped

  db:
    # Postgres 17 with the vector extension Grimoire needs.
    image: pgvector/pgvector:pg17
    stop_grace_period: 120s
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-grimoire}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-grimoire}
      POSTGRES_DB: ${POSTGRES_DB:-grimoire}
    restart: unless-stopped

volumes:
  app_data:
  pgdata:

Open http://localhost:5000. The first account you register becomes the admin.

Nothing has to be set first. On its first start Grimoire makes its own SECRET_KEY and keeps it in the app_data volume, so restarts, reboots and updates all use the same key.

To connect Claude, create an API key under Settings → MCP Access, then in Claude Code:

/plugin marketplace add https://git.fabledsword.com/bvandeusen/FabledGrimoire.git
/plugin install grimoire@grimoire-plugin

The plugin asks for your Grimoire URL and the API key. Settings → MCP Access shows the exact commands for your instance.

Configuration

Everything is optional. Set these in the environment or in a .env file beside the compose file:

Variable When What it does
BASE_URL Behind a proxy The public URL, used in email links and SSO redirects
SECURE_COOKIES Over HTTPS true when Grimoire is served over HTTPS
TRUST_PROXY_HEADERS Behind a proxy true to read the client address from the proxy's headers
POSTGRES_PASSWORD Before the first start The database password (defaults to grimoire; the database is reachable only inside the compose network). Postgres takes it once, when the volume is created
SECRET_KEY Rarely A key you manage yourself, instead of the one Grimoire keeps. It wins over the kept key; remove it to go back

Everything else (registration, email, SSO, git forge connections, retrieval tuning, backups) is in Settings, or listed in Configuration.

Setup pitfalls

  • Keep both volumes. pgdata holds everything Grimoire stores. app_data holds the instance's key, and forge tokens and the backup bucket's secret are sealed under it. If the key is lost, Settings asks you to enter those credentials again; nothing else is lost.
  • The embedding model downloads on first use, into the app_data volume. Without internet access, semantic search falls back to keyword search until the model is in place.
  • Behind a reverse proxy, turn off response buffering for /mcp, because MCP responses stream. Configuration has an Nginx example.

Updating and backups

docker compose pull
docker compose up -d

Database migrations run when the app starts, and the key stays in its volume. Claude Code updates the plugin from its marketplace; run /reload-plugins after an update.

Settings → Data → Scheduled backups writes a daily backup of the database to a folder or an S3-compatible bucket, and python -m grimoire.restore brings a fresh instance back from one. See Backups.

Features

Working with Claude

  • Claude enters a project and gets a short primer: its goal, current plans, open tasks and areas.
  • Your rules reach Claude when its work matches them, or at a moment of work such as finishing a task or pushing code.
  • Before Claude writes a file or runs a command, the plugin shows it the rules, lessons and reusable code that may apply.
  • Stored procedures, such as a drift audit, become Claude Code skills.

Recording the work

  • Notes in a Markdown editor, with wikilinks, tags and version history.
  • Tasks, issues and time-boxed investigations, with work logs that the next session reads first.
  • Plans as milestones: a design plus ordered steps.
  • Lessons learned the hard way, linked to the rules they illustrate.
  • Duplicate checks, so a new record that matches an existing one updates it instead.

Reusing code

  • Snippets of reusable code, each with when to reach for it and where it lives in the repo.
  • With a git forge connected, Grimoire tracks every function and style in your repos and shows which ones are still unaccounted for.
  • Ideas shared across projects on the same platform, with each project's answer recorded.
  • Design systems with tokens, inheritance and a generated stylesheet.

For people

  • A web UI to browse, search and edit everything, plus a graph of how notes connect.
  • Sharing with users and groups, as viewer, editor or admin.
  • Email and password sign-in, optional SSO through OIDC, and invite links.
  • Personal export to Markdown or JSON, and admin backup and restore.

The full list is in Features.

Troubleshooting

What you see Why Fix
SECRET_KEY is set to the public placeholder at startup SECURE_COOKIES=true while SECRET_KEY is dev-secret-change-me Remove SECRET_KEY, or set a real one
Settings asks for forge tokens or the backup secret again The instance's key changed: the app_data volume was replaced, or SECRET_KEY was set or removed Enter them again, or restore the previous key
Can't locate revision identified by '…' at startup An older image is running against a database a newer one has already migrated Run the newer image; migrations only move forward
The plugin's tools are missing in Claude Code The plugin isn't installed, or Claude Code hasn't reloaded it /plugin to install or update it, then /reload-plugins
Search finds only exact words The embedding model hasn't downloaded yet Give the app internet access once, or wait for the first download to finish

Development

docker compose -f docker-compose.dev.yml up --build

Development covers checks, migrations, the plugin and CI. Architecture describes how it is built, and the API reference lists every REST endpoint.

Licence

Fabled Grimoire is free software under the GNU Affero General Public License v3.0 only (AGPL-3.0-only). If you run a modified version for other people over a network, the licence requires you to offer them its source.

S
Description
No description provided
Readme AGPL-3.0
23 MiB
Languages
Python 79.2%
Vue 14.3%
TypeScript 2.8%
Shell 2.4%
CSS 1%
Other 0.2%