• v26.06.01.2 — Rules consolidation + project rule suppressions
    CI & Build / Python lint (push) Successful in 3s
    CI & Build / TypeScript typecheck (push) Successful in 33s
    CI & Build / Python tests (push) Successful in 48s
    CI & Build / Build & push image (push) Successful in 22s
    Stable

    bvandeusen released this 2026-06-01 08:11:45 -04:00 | 109 commits to main since this release

    Rules subsystem matures from "additive cross-project rulebooks only" into a full first-class system: always-on rulebooks, project-scoped rules, an active-project handshake, and per-project suppression of inherited rules. Two PRs since v26.06.01.1.

    PR #53 — Rules consolidation (4 slices)

    Problem. Rules in Scribe were pull-only; CLAUDE.md and ~/.claude/.../memory/feedback_*.md were session-start auto-loaded. The MCP prompt never insisted that Claude fetch Scribe rules eagerly or codify new rules in Scribe rather than the competing stores. Result: Scribe rules silently lost.

    • S1 + S2 — always_on rulebook flag (commit 658348f)

      • Migration 0058: rulebooks.always_on boolean. FabledSword family rulebook seeded always_on=true at migrate-time.
      • New MCP tool list_always_on_rules() returns the union of standing rules for the user in one round-trip, no active-project needed.
      • _INSTRUCTIONS rewritten: at session start, call list_always_on_rules; treat as binding. Rules codified in Scribe via create_rule, never in CLAUDE.md or feedback files. Those stores are now scoped to user-facts and codebase onboarding respectively.
      • Frontend: badge on always-on rulebooks in RulebookListPane; toggle in RulebookDetailPane header.
    • S3 — Project-scoped rules (commit 43a860c)

      • Migration 0059: rules.project_id (nullable FK, CASCADE), rules.topic_id made nullable, CHECK ck_rule_topic_xor_project enforces exactly-one.
      • New MCP tool create_project_rule(project_id, statement, title?, why?, how_to_apply?) — no rulebook ceremony for project-only rules.
      • get_applicable_rules adds a project_rules field surfaced through get_project, get_task (plan), start_planning.
      • Trash cascade: deleting a project soft-deletes its project-scoped rules along with the rest.
      • REST: POST /api/projects/<id>/rules; frontend Rules-tab gains a "Project rules" section with inline create form.
    • S4 — enter_project handshake (commit c546921)

      • New MCP tool enter_project(project_id) composes get_project + get_applicable_rules + milestone-summary + open-tasks + recent-notes into one round-trip. Intended for once-per-session use when work is project-scoped.
      • _INSTRUCTIONS directs Claude to call it before any project-scoped mutation.
      • No schema change; pure composition over existing services.

    PR #54 — Project rule + topic suppressions (commit 7861607)

    Lets a project mute individual rules or whole topics from rulebooks it subscribes to, without unsubscribing the rulebook. Use case: subscribe to a broad rulebook (e.g. a future "FabledSword design system") but opt out of one or two rules — or a whole topic — that doesn't apply to a non-frontend project.

    • Schema (migration 0060): two new pure m2m association tables — project_rule_suppressions and project_topic_suppressions. PKs on both columns; FKs CASCADE. No deleted_at — pure associations, hard-deleted on project trash.
    • MCP tools (4): suppress_rule_for_project, unsuppress_rule_for_project, suppress_topic_for_project, unsuppress_topic_for_project. All idempotent; verify project + rule/topic ownership. Project-scoped rules (Rule.project_id) are deliberately not suppressible — delete them instead.
    • REST: POST/DELETE /api/projects/<pid>/suppressions/{rules,topics}/<id>.
    • Service projection: get_applicable_rules runs two extra queries and emits suppressed_rules + suppressed_topics as detail objects (id + title + rulebook context, not bare IDs — so the UI doesn't need a follow-up lookup). The main rules list is filtered SQL-side so truncated reflects post-suppression count. Rules now carry topic_id + rulebook_id columns for the UI affordance.
    • Propagation: suppressed_rules and suppressed_topics surface through get_project, enter_project, get_task (plan), and start_planning — Claude sees what's muted from any standard handshake.
    • Frontend: "× skip" affordance reveals on hover for each rule row and each topic header in ProjectRulesTab.vue; collapsed "Suppressed (N)" section at the bottom with per-item "↻ re-enable" buttons. groupByRulebookAndTopic refactored to id-bearing structs.
    • Trash cascade: project deletion hard-deletes the project's suppression rows so a later restore starts fresh.

    Migrations

    • 0058rulebooks.always_on boolean, default false; seeds FabledSword family to true.
    • 0059rules.project_id (FK CASCADE), rules.topic_id nullable, CHECK ck_rule_topic_xor_project. Down-migration requires migrating/deleting project-scoped rules first.
    • 0060project_rule_suppressions and project_topic_suppressions association tables.

    All three run automatically on first boot.

    Verification

    • CI green on c546921 (S4 — after rebuild; original run flaked on npm-cache action), 43a860c (S3), 658348f (S1+S2), and 7861607 (suppressions).
    • Migrations 0058/0059/0060 applied cleanly to the dev environment; operator confirmed the suppression UI and MCP tools work end-to-end on dev (migration in dev worked, 2026-06-01).
    • Tests cover: list_always_on_rules, update_rulebook(always_on=…), create_project_rule (required-fields + title-derivation + explicit-title), enter_project composed shape + 404, get_applicable_rules with project_rules + suppressed_rules + suppressed_topics, project-cascade trash hitting 7 tables (was 4 before S3, 5 after S3, 7 with this release).

    Deploy notes

    • Three migrations run automatically on container start.
    • After deploy, MCP reconnects pick up the new _INSTRUCTIONS; on the next project-scoped turn Claude should call list_always_on_rules and enter_project. Eyeball the tool-call transcript on first use.
    • No content migration: rule-shaped entries in CLAUDE.md and feedback memory files stay where they are. The prompt reroutes NEW rules to Scribe going forward.

    What this release does NOT do

    • No supersede semantics — a project rule can't yet replace a rulebook rule for one project (only mute it). Pure suppression covers the stated use case; replacement can land later.
    • No write-scope enforcement on bearer tokens — mutating tools still ignore the read/write scope on api_keys. M1 work, tracked separately.
    • No share-aware filtering on list_trash / restore / purge — same M1 carve-out.
    Downloads