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
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:
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -39,7 +39,7 @@ router.afterEach(() => {
|
||||
<!-- Left: brand -->
|
||||
<router-link to="/" class="nav-brand">
|
||||
<AppLogo :size="34" />
|
||||
<span class="brand-text">Scribe</span>
|
||||
<span class="brand-text">Grimoire</span>
|
||||
</router-link>
|
||||
|
||||
<!-- Center: primary navigation (desktop) -->
|
||||
|
||||
@@ -189,7 +189,7 @@ async function backUpNow() {
|
||||
<p class="intro">
|
||||
Each run adds one dated file, <code>scribe-<date>.tar</code>, 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.
|
||||
</p>
|
||||
|
||||
@@ -223,7 +223,7 @@ async function backUpNow() {
|
||||
<span>Folder</span>
|
||||
<input v-model.trim="form.folder_path" class="fs-input" placeholder="/backups" />
|
||||
<span class="field-hint">
|
||||
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.
|
||||
</span>
|
||||
</label>
|
||||
|
||||
@@ -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'"
|
||||
>
|
||||
<code>{{ actionLabel(a) }}</code>
|
||||
<button
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* someone changes the shared value and half the components don't move.
|
||||
*
|
||||
* SCOPE, and it is a limit rather than an omission: this reads RECORDED code —
|
||||
* snippets — because that is the code Scribe holds. A repository's own sources
|
||||
* snippets — because that is the code Grimoire holds. A repository's own sources
|
||||
* are checked where they live, by that project's CI.
|
||||
*/
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
|
||||
@@ -49,7 +49,7 @@ const label = (s: string) => LABELS[s] ?? s;
|
||||
Measured worst-case over raised and hover in both modes: active 4.82:1,
|
||||
paused 4.63:1, completed 4.78:1, archived 4.84:1.
|
||||
No new design tokens: four values used by one component are the kind of
|
||||
growth Scribe's own design-system note warns about ("if this system grows
|
||||
growth Grimoire's own design-system note warns about ("if this system grows
|
||||
past a handful of tokens, that is worth noticing rather than
|
||||
accommodating"). The derivation is stated once, here. */
|
||||
.project-status--active {
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { RulePreset } from "@/api/rulebooks";
|
||||
import RuleEditorSlideOver from "@/components/rules/RuleEditorSlideOver.vue";
|
||||
|
||||
/**
|
||||
* The reply shapes Scribe ships, and the operator's adjustments to each
|
||||
* The reply shapes Grimoire ships, and the operator's adjustments to each
|
||||
* A shape is product, so its text is read-only here;
|
||||
* what the operator owns is the preferences mounted on the shape's moment,
|
||||
* which arrive beside it and win where they differ. "Adjust this" opens the
|
||||
@@ -39,7 +39,7 @@ const delivered = computed(() =>
|
||||
const verdict = computed(() => {
|
||||
if (!data.value) return "";
|
||||
const n = shapes.value.length;
|
||||
const parts = [`${n} ${n === 1 ? "shape ships" : "shapes ship"} with Scribe`];
|
||||
const parts = [`${n} ${n === 1 ? "shape ships" : "shapes ship"} with Grimoire`];
|
||||
parts.push(adjusted.value
|
||||
? `${adjusted.value} adjusted by your preferences`
|
||||
: "none adjusted — the defaults stand");
|
||||
@@ -126,7 +126,7 @@ onMounted(load);
|
||||
</button>
|
||||
|
||||
<div v-if="open === s.key" :id="`shape-${s.key}`" class="shape-body">
|
||||
<h4 class="body-label">Ships with Scribe · at <code>{{ s.moment }}</code></h4>
|
||||
<h4 class="body-label">Ships with Grimoire · at <code>{{ s.moment }}</code></h4>
|
||||
<div class="shape-text">{{ s.text }}</div>
|
||||
|
||||
<h4 class="body-label">Your adjustments</h4>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* What Scribe has changed about how it works with you.
|
||||
* What Grimoire has changed about how it works with you.
|
||||
*
|
||||
* THE RISK THIS EXISTS FOR. A preference is the one record
|
||||
* kind the agent rewrites on its own, mid-work, without asking — which is
|
||||
@@ -78,7 +78,7 @@ onMounted(() => store.fetchDrift());
|
||||
<header>
|
||||
<h2>Recent changes</h2>
|
||||
<p class="sweep-lede">
|
||||
Preferences Scribe rewrote while working, most recently changed first. A
|
||||
Preferences Grimoire rewrote while working, most recently changed first. A
|
||||
preference is how you want work done, so sessions keep it current
|
||||
without asking — this is where you see what they decided. Rules are not
|
||||
here: those change when you change them.
|
||||
|
||||
@@ -261,7 +261,7 @@ watch(() => props.ruleId, load);
|
||||
<input v-model="kind" type="radio" value="preference" />
|
||||
<span>
|
||||
<strong>Preference</strong> — how you want work done. Ignoring it
|
||||
costs consistency, not correctness, and <em>Scribe updates it as
|
||||
costs consistency, not correctness, and <em>Grimoire updates it as
|
||||
the work teaches it</em>.
|
||||
</span>
|
||||
</label>
|
||||
|
||||
@@ -25,7 +25,7 @@ const emit = defineEmits<{
|
||||
<span
|
||||
v-if="r.kind === 'preference'"
|
||||
class="rule-chip rule-chip-preference"
|
||||
title="How you want work done. It does not bind, and Scribe updates it as the work teaches it."
|
||||
title="How you want work done. It does not bind, and Grimoire updates it as the work teaches it."
|
||||
>preference</span>
|
||||
<!-- Marked only when something is WRONG: every rule arrives by
|
||||
retrieval now, so "conditional" stopped distinguishing anything.
|
||||
|
||||
@@ -208,7 +208,7 @@ export const useRulebooksStore = defineStore("rulebooks", () => {
|
||||
}
|
||||
|
||||
/**
|
||||
* What Scribe has changed about how it works with the operator.
|
||||
* What Grimoire has changed about how it works with the operator.
|
||||
*
|
||||
* Preferences only — a rule changes when its author changes it, so
|
||||
* including them would bury the unreviewed rows under the operator's own
|
||||
|
||||
@@ -498,8 +498,8 @@ watch(selectedId, () => {
|
||||
* The provenance list below shows values as the record states them, and a
|
||||
* `var()` reference states nothing on its own: rendering
|
||||
* `color-mix(in srgb, var(--accent) 15%, transparent)` as a background resolves
|
||||
* `--accent` against THIS app, so a system that isn't the one Scribe runs on
|
||||
* would be drawn in Scribe's palette — and look right, which is why it would
|
||||
* `--accent` against THIS app, so a system that isn't the one Grimoire runs on
|
||||
* would be drawn in Grimoire's palette — and look right, which is why it would
|
||||
* go unnoticed.
|
||||
*
|
||||
* The preview above resolves values properly, on a probe carrying only that
|
||||
|
||||
@@ -901,7 +901,7 @@ async function confirmDelete() {
|
||||
<div class="edit-field">
|
||||
<label class="edit-label">Goal</label>
|
||||
<!-- A textarea, not a single-line input. A project goal is a
|
||||
paragraph in practice — this one showed as "Maintain Scribe as
|
||||
paragraph in practice — this one showed as "Maintain Grimoire as
|
||||
the reliabl" and gave no way to read the rest without arrowing
|
||||
through it. -->
|
||||
<textarea v-model="editGoal" class="fs-input edit-textarea" rows="4" placeholder="What are you trying to achieve?"></textarea>
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user