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
+20 -20
View File
@@ -254,7 +254,7 @@ interface TuningEvent {
// What a dial's number was measured against, and whether that space has moved
// Mirrors the `calibration` block `current_settings` returns per dial.
// `stale` is nullable on purpose: a dial moved before Scribe recorded stamps is
// `stale` is nullable on purpose: a dial moved before Grimoire recorded stamps is
// UNKNOWN rather than fine, and rendering the two the same would hide the case
// most likely to be wrong.
interface DialCalibration {
@@ -289,7 +289,7 @@ const staleDials = computed(() =>
dial,
why:
cal.source === "unstamped"
? "changed before Scribe recorded what it was measured against"
? "changed before Grimoire recorded what it was measured against"
: cal.model_changed && cal.shape_changed
? `measured under ${cal.embedding_model} at document shape ${cal.shape_version} — both have changed since`
: cal.model_changed
@@ -599,9 +599,9 @@ const claudeCodeCommand = computed(() => {
--header "Authorization: Bearer ${effectiveApiKey.value}"`;
});
// Plugin install — the recommended path. The Scribe plugin bundles the MCP
// connection, a session-start hook that surfaces your rules, and the Scribe
// process-skills. The marketplace is the Scribe app's own git repo; persisted
// Plugin install — the recommended path. The Grimoire plugin bundles the MCP
// connection, a session-start hook that surfaces your rules, and the Grimoire
// process-skills. The marketplace is the Grimoire app's own git repo; persisted
// per-browser like the MCP fields above.
const _MKT_KEY = 'plugin_marketplace_url';
const pluginMarketplaceUrl = ref<string>(localStorage.getItem(_MKT_KEY) || '');
@@ -799,7 +799,7 @@ const smtp = ref({
smtp_username: "",
smtp_password: "",
smtp_from_address: "",
smtp_from_name: "Fabled Scribe",
smtp_from_name: "Fabled Grimoire",
smtp_use_tls: "true",
});
const savingSmtp = ref(false);
@@ -1319,7 +1319,7 @@ async function handleRestoreFile(event: Event) {
if (res.status === 413) {
throw new Error(
"the file is bigger than the web upload allows. Restore it with " +
"`python -m scribe.restore <file>` inside the Scribe container instead.",
"`python -m scribe.restore <file>` inside the Grimoire container instead.",
);
}
if (!res.ok) {
@@ -1677,7 +1677,7 @@ async function deleteUser(userId: number) {
<section class="settings-section full-width">
<h2>Knowledge auto-inject</h2>
<p class="section-desc">
When enabled, the Scribe plugin quietly surfaces the titles of your most
When enabled, the Grimoire plugin quietly surfaces the titles of your most
relevant notes on each prompt — never their full text — so Claude can pull
one in with <code>get_note(id)</code> only when it helps. Titles only, each
note at most once per session, and nothing is shown unless it clears the
@@ -1980,7 +1980,7 @@ async function deleteUser(userId: number) {
</p>
<p v-if="loadingTuning" class="field-hint">Loading…</p>
<p v-else-if="!tuningEvents.length" class="field-hint">
Nothing has been changed yet — every surface is on the value Scribe
Nothing has been changed yet — every surface is on the value Grimoire
shipped. Those are starting points measured against one corpus with
one embedding model, not answers, so expect this to fill.
</p>
@@ -2519,7 +2519,7 @@ async function deleteUser(userId: number) {
<section class="settings-section full-width">
<h2>MCP Access</h2>
<p class="settings-description">
Connect Claude (Code or Desktop) to this Scribe instance. Claude reads and writes your notes,
Connect Claude (Code or Desktop) to this Grimoire instance. Claude reads and writes your notes,
tasks, projects, events, and people via the built-in MCP endpoint below.
</p>
@@ -2625,8 +2625,8 @@ async function deleteUser(userId: number) {
<!-- Claude Code tab -->
<div v-if="mcpClientTab === 'claude-code'">
<p class="settings-description">
<strong>Recommended — install the Scribe plugin.</strong> One install wires up the MCP
connection, a session-start hook that surfaces your rules, and the Scribe process-skills.
<strong>Recommended — install the Grimoire plugin.</strong> One install wires up the MCP
connection, a session-start hook that surfaces your rules, and the Grimoire process-skills.
</p>
<ol>
<li>
@@ -2639,7 +2639,7 @@ async function deleteUser(userId: number) {
</div>
</li>
<li>
When prompted, enter your <strong>Scribe base URL</strong> (<code>{{ origin }}</code>),
When prompted, enter your <strong>Grimoire base URL</strong> (<code>{{ origin }}</code>),
an <strong>API key</strong> (generate one above), and optionally a
<strong>project id</strong> to scope the session-start context.
</li>
@@ -2657,7 +2657,7 @@ async function deleteUser(userId: number) {
<input
v-model="pluginMarketplaceUrl"
type="text"
:placeholder="serverMarketplaceUrl || 'https://git.example.com/you/Scribe.git'"
:placeholder="serverMarketplaceUrl || 'https://git.example.com/you/Grimoire.git'"
class="settings-input"
spellcheck="false"
/>
@@ -2687,7 +2687,7 @@ async function deleteUser(userId: number) {
<p class="mcp-hint" style="margin-top: 0.75rem;">
<strong>Connect the MCP only (no plugin).</strong> You won't get the session-start rule
push or the Scribe skills this way.
push or the Grimoire skills this way.
</p>
<div class="mcp-code-row">
<pre class="mcp-code">{{ claudeCodeCommand }}</pre>
@@ -2721,7 +2721,7 @@ async function deleteUser(userId: number) {
</div>
</li>
<li>
Restart Claude Desktop. The Scribe tools should appear in the available tools list.
Restart Claude Desktop. The Grimoire tools should appear in the available tools list.
</li>
</ol>
</div>
@@ -2799,9 +2799,9 @@ async function deleteUser(userId: number) {
<section class="settings-section full-width">
<h2>Plugin marketplace</h2>
<p class="section-desc">
Git URL of the repo that ships this Scribe plugin (usually this app's own repo).
Git URL of the repo that ships this Grimoire plugin (usually this app's own repo).
Shown to every user in <strong>MCP Access</strong> so the install command is
copyable. Example: https://git.example.com/you/Scribe.git
copyable. Example: https://git.example.com/you/Grimoire.git
</p>
<div class="field url-field">
<label for="marketplace-url">Marketplace git URL</label>
@@ -2809,7 +2809,7 @@ async function deleteUser(userId: number) {
id="marketplace-url"
v-model="adminMarketplaceUrl"
type="url"
placeholder="https://git.example.com/you/Scribe.git"
placeholder="https://git.example.com/you/Grimoire.git"
class="fs-input input"
/>
</div>
@@ -2927,7 +2927,7 @@ async function deleteUser(userId: number) {
</div>
<div class="field">
<label for="smtp-from-name">From Name</label>
<input id="smtp-from-name" v-model="smtp.smtp_from_name" type="text" placeholder="Fabled Scribe" class="fs-input input" />
<input id="smtp-from-name" v-model="smtp.smtp_from_name" type="text" placeholder="Fabled Grimoire" class="fs-input input" />
</div>
</div>
<div class="checkbox-field">