docs(mcp): encode rule-scope model in rulebook tool descriptions
Make the always-on / subscribed / project-rule distinction explicit at the authoring surface so it can't silently regress (for this operator or other users). Previously the tools said only 'cross-project rulebook rule' and a bare 'subscribe a project' — nothing steered project-specific detail away from shared rulebooks, which is how a Scribe-pinned rule ends up binding every family project. Principle encoded in 5 places: a rule's home is chosen by WHO it should bind, and both rulebook tiers are SHARED so their rules stay general — they differ in reach (all projects vs opt-in by theme), not generality. Project-specific detail goes in create_project_rule. - server.py MCP instructions: add the 3-tier authoring principle - create_rule / create_rulebook / create_project_rule / subscribe_* docstrings - using-scribe SKILL.md: a 'Where a new rule goes' note for the pull path Refs #755 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -48,6 +48,25 @@ explicit pull. Rules loaded this way are **binding** for the session.
|
|||||||
5. **Keep state honest.** Set a task `in_progress` when you start it, `done` the
|
5. **Keep state honest.** Set a task `in_progress` when you start it, `done` the
|
||||||
moment it's complete; log progress as you go.
|
moment it's complete; log progress as you go.
|
||||||
|
|
||||||
|
## Where a new rule goes
|
||||||
|
|
||||||
|
When codifying a rule, pick its home by **who it should bind** — and keep
|
||||||
|
shared homes general:
|
||||||
|
|
||||||
|
- **Always-on rulebook** (`create_rule` in an `always_on` rulebook) — universal
|
||||||
|
norms that bind *every* project. Cross-project standards only.
|
||||||
|
- **Subscribed rulebook** (`create_rule` + `subscribe_project_to_rulebook`) — a
|
||||||
|
reusable, *themed* module of general rules that binds only projects that opt
|
||||||
|
in (e.g. a design system → visual apps). Themed, but still project-agnostic.
|
||||||
|
- **Project rule** (`create_project_rule`) — anything specific to one project
|
||||||
|
(its files, paths, quirks).
|
||||||
|
|
||||||
|
Both rulebook tiers are shared, so their rules stay general; they differ in
|
||||||
|
**reach** (all vs opt-in), not generality. Names one project's specifics →
|
||||||
|
project rule; a standard a category shares → subscribed rulebook; a universal
|
||||||
|
norm → always-on rulebook. Never put project-specific detail in a shared
|
||||||
|
rulebook — it leaks to every other project that gets it.
|
||||||
|
|
||||||
## Other Scribe process-skills
|
## Other Scribe process-skills
|
||||||
|
|
||||||
This plugin also ships focused process-skills — brainstorming, systematic
|
This plugin also ships focused process-skills — brainstorming, systematic
|
||||||
|
|||||||
@@ -82,8 +82,24 @@ new engineering rules to CLAUDE.md or to ~/.claude/.../memory/feedback_*.md
|
|||||||
— those stores are reserved for facts about the user (preferences, role,
|
— those stores are reserved for facts about the user (preferences, role,
|
||||||
communication style) and codebase onboarding pointers, respectively. Before
|
communication style) and codebase onboarding pointers, respectively. Before
|
||||||
creating a rule, call list_always_on_rules and list_rules(project_id=...) to
|
creating a rule, call list_always_on_rules and list_rules(project_id=...) to
|
||||||
avoid duplicates. Coordinate with the operator on whether a new rule belongs
|
avoid duplicates.
|
||||||
in a project, an existing rulebook+topic, or a new rulebook.
|
|
||||||
|
Choose a rule's home by WHO it should bind, and keep each home's rules at the
|
||||||
|
right altitude:
|
||||||
|
- Always-on rulebook (a rulebook flagged always_on) — universal norms that
|
||||||
|
bind EVERY one of your projects. Reserve for cross-project standards.
|
||||||
|
- Subscribed rulebook (always_on off; projects opt in via
|
||||||
|
subscribe_project_to_rulebook) — a reusable, THEMED module of general
|
||||||
|
rules that binds only the projects which subscribe. Its rules must make
|
||||||
|
sense for every project that could subscribe, never one specific project
|
||||||
|
(e.g. a design-system rulebook: design-specific but project-agnostic — no
|
||||||
|
rule names a single app).
|
||||||
|
- Project rule (create_project_rule) — anything specific to ONE project.
|
||||||
|
Both rulebook tiers are SHARED, so their rules stay general; the difference
|
||||||
|
between them is REACH (all projects vs opt-in by theme), not generality. Rule
|
||||||
|
of thumb: names a specific project's files/paths/quirks -> project rule; a
|
||||||
|
standard a CATEGORY of projects shares -> subscribed rulebook; a universal
|
||||||
|
norm -> always-on rulebook. Coordinate with the operator on which home fits.
|
||||||
|
|
||||||
That boundary cuts the other way too. Because rules are pull-only, a fresh
|
That boundary cuts the other way too. Because rules are pull-only, a fresh
|
||||||
session won't reach for them unless its always-loaded context says to. So
|
session won't reach for them unless its always-loaded context says to. So
|
||||||
|
|||||||
@@ -39,7 +39,18 @@ async def get_rulebook(rulebook_id: int) -> dict:
|
|||||||
|
|
||||||
|
|
||||||
async def create_rulebook(title: str, description: str = "") -> dict:
|
async def create_rulebook(title: str, description: str = "") -> dict:
|
||||||
"""Create a new rulebook.
|
"""Create a new rulebook (a shared, reusable module of general rules).
|
||||||
|
|
||||||
|
Two ways a rulebook reaches projects, set by its always_on flag (toggle via
|
||||||
|
update_rulebook):
|
||||||
|
- always_on = true -> binds EVERY one of your projects automatically.
|
||||||
|
Use for universal cross-project norms (e.g. "FabledSword family").
|
||||||
|
- always_on = false -> binds only projects that subscribe
|
||||||
|
(subscribe_project_to_rulebook). Use for a THEMED body of rules a
|
||||||
|
category of projects shares (e.g. a design system that visual apps
|
||||||
|
opt into).
|
||||||
|
Either way a rulebook is SHARED, so its rules must stay general — agnostic
|
||||||
|
to any single project. Project-specific rules go in create_project_rule.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
title: Rulebook name (e.g. "FabledSword family").
|
title: Rulebook name (e.g. "FabledSword family").
|
||||||
@@ -247,7 +258,15 @@ async def create_rule(
|
|||||||
topic_id: int, title: str, statement: str,
|
topic_id: int, title: str, statement: str,
|
||||||
why: str = "", how_to_apply: str = "", order_index: int = 0,
|
why: str = "", how_to_apply: str = "", order_index: int = 0,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Create a new rule under a topic (cross-project rulebook rule).
|
"""Create a new rule in a rulebook (a SHARED rule — keep it general).
|
||||||
|
|
||||||
|
A rulebook rule is shared by every project that gets the rulebook: an
|
||||||
|
always_on rulebook binds ALL your projects; a subscribed rulebook binds the
|
||||||
|
projects that opt in. So a rulebook rule must read as a general standard —
|
||||||
|
never pin it to one project's files, paths, or quirks. For a rule that
|
||||||
|
applies to a single project only, use create_project_rule instead (no
|
||||||
|
rulebook+topic ceremony). If it's a standard a CATEGORY of projects shares,
|
||||||
|
put it in a themed subscribed rulebook, not the always-on one.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
topic_id: The topic to attach the rule to.
|
topic_id: The topic to attach the rule to.
|
||||||
@@ -256,9 +275,6 @@ async def create_rule(
|
|||||||
why: Optional rationale — the reason the rule exists.
|
why: Optional rationale — the reason the rule exists.
|
||||||
how_to_apply: Optional operationalization — when / where it kicks in.
|
how_to_apply: Optional operationalization — when / where it kicks in.
|
||||||
order_index: Display order within the topic (default 0).
|
order_index: Display order within the topic (default 0).
|
||||||
|
|
||||||
For a rule that applies to a single project only, use create_project_rule
|
|
||||||
instead — no rulebook+topic ceremony required.
|
|
||||||
"""
|
"""
|
||||||
uid = current_user_id()
|
uid = current_user_id()
|
||||||
rule = await rulebooks_svc.create_rule(
|
rule = await rulebooks_svc.create_rule(
|
||||||
@@ -275,9 +291,13 @@ async def create_project_rule(
|
|||||||
) -> dict:
|
) -> dict:
|
||||||
"""Create a rule scoped to a single project (no rulebook needed).
|
"""Create a rule scoped to a single project (no rulebook needed).
|
||||||
|
|
||||||
Use this when a rule only applies to one project — it bypasses the
|
Use this for anything SPECIFIC to one project — its files, paths, layout,
|
||||||
Rulebook -> Topic -> Rule ceremony. The rule is returned in get_project's
|
or quirks. This is the correct home for the project-specific detail that
|
||||||
applicable_rules (under project_rules) and in list_rules(project_id=...).
|
must NOT go into a shared rulebook (where it would leak to every other
|
||||||
|
project that gets the rulebook). General standards belong in a rulebook
|
||||||
|
instead (create_rule). It bypasses the Rulebook -> Topic -> Rule ceremony;
|
||||||
|
the rule is returned in get_project's applicable_rules (under
|
||||||
|
project_rules) and in list_rules(project_id=...).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
project_id: The project to attach the rule to.
|
project_id: The project to attach the rule to.
|
||||||
@@ -345,7 +365,14 @@ async def delete_rule(rule_id: int, confirmed: bool = False) -> dict:
|
|||||||
async def subscribe_project_to_rulebook(
|
async def subscribe_project_to_rulebook(
|
||||||
project_id: int, rulebook_id: int,
|
project_id: int, rulebook_id: int,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Subscribe a project to a rulebook. Its rules will apply to that project."""
|
"""Subscribe a project to a rulebook — its rules then bind that project.
|
||||||
|
|
||||||
|
Subscription is the opt-in path for a non-always_on rulebook: a reusable,
|
||||||
|
themed module of GENERAL rules shared across the projects that subscribe.
|
||||||
|
Subscribe a project because it fits the rulebook's theme (e.g. a visual app
|
||||||
|
-> the design-system rulebook), not to host rules about this one project —
|
||||||
|
those belong in create_project_rule.
|
||||||
|
"""
|
||||||
uid = current_user_id()
|
uid = current_user_id()
|
||||||
await rulebooks_svc.subscribe_project(
|
await rulebooks_svc.subscribe_project(
|
||||||
project_id=project_id, rulebook_id=rulebook_id, user_id=uid,
|
project_id=project_id, rulebook_id=rulebook_id, user_id=uid,
|
||||||
|
|||||||
Reference in New Issue
Block a user