chore(design-systems): stop teaching one install's kit in product copy
CI & Build / Python lint (push) Successful in 5s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / integration (push) Successful in 27s
CI & Build / TypeScript typecheck (push) Successful in 36s
CI & Build / Python tests (push) Successful in 49s
CI & Build / Build & push image (push) Successful in 41s

The operator's check: this must be a system for managing design systems, not one
with the FabledSword family built into it.

No LOGIC was coupled — the audit found zero behavioural dependencies. But every
docstring example, every UI placeholder and several comments named this install's
palette, so a stranger creating their first design system was shown
"FabledSword" as the expected shape and `--fs-obsidian` as the expected token.
Examples teach, and these taught the wrong thing.

Placeholders now describe the SHAPE ("Your house style", "--surface-page")
rather than naming one instance's contents, and the token-name placeholder now
says the thing worth saying: name it for its purpose, because `--obsidian` and
`--button-bg` both stop being true the moment the value or the element changes.

Not fixed here, and it is the one real coupling left: DesignView.vue hardcodes
rule 65's button variants and rule 60's type scale as literal arrays, so a
stranger's Design page would display this family's specs. Those arrays exist
because there was no design system to read from — which there now is. They go
when the panel is repointed (#2295), not before.

Scribe's own stylesheet comments ("Moss action-primary per Hybrid") are left
alone: that is the app CONSUMING the family style, which is what dogfooding
looks like, not the tool assuming it.
This commit is contained in:
2026-07-31 10:18:53 -04:00
parent 1fde646c60
commit 473280e690
5 changed files with 32 additions and 23 deletions
+11 -6
View File
@@ -33,7 +33,8 @@ async def create_design_system(
"""Create a design system, optionally inheriting from another.
Args:
title: What this system is, e.g. "FabledSword" or "Scribe" (required).
title: What this system is — a house style, or one app within it
(required).
description: What it covers and when it applies.
guidance: The narrative a token table cannot hold — aesthetic, voice and
tone, what is deliberately out of scope. Markdown, free-form.
@@ -226,18 +227,22 @@ async def create_design_token(
Args:
design_system_id: The system that owns this token.
name: The custom-property name, e.g. "--fs-obsidian" (required).
name: The custom-property name, e.g. "--surface-page" (required).
Name it for its PURPOSE, not its value: a name like "--obsidian"
or "--button-bg" stops being true the moment the value or the
element changes.
value_by_mode: Values keyed by mode, e.g.
{"base": "#f7f5ef", "dark": "#14171a"}. Use "base" for the value
{"base": "#14171a", "light": "#f7f5ef"}. Use "base" for the value
that applies when no mode is more specific; a token that is not
mode-dependent needs only "base". In a system WITH a parent, an
omitted mode is inherited rather than blanked.
group_name: Free-text grouping — "surface", "text", "radius", whatever
this system's own vocabulary is.
purpose: What the token is for, e.g. "page bg, deepest surface".
purpose: What the token is for, e.g. "page background, deepest
surface".
rationale: WHY it is this value — a different question from purpose.
"Success equals Moss, aligned by design" is a rationale; "page bg,
deepest surface" is a purpose.
"Deliberately the same value as the primary action colour" is a
rationale; "page background, deepest surface" is a purpose.
supersedes: Literal values this token should be used INSTEAD OF, e.g.
["#fff", "#ffffff"]. This is how a design system records what a
prohibition was trying to say — not "white is banned" but "write
+3 -2
View File
@@ -45,7 +45,8 @@ async def create_rulebook(title: str, description: str = "") -> dict:
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").
Use for universal cross-project norms that apply across every
project, not just one.
- 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
@@ -54,7 +55,7 @@ async def create_rulebook(title: str, description: str = "") -> dict:
to any single project. Project-specific rules go in create_project_rule.
Args:
title: Rulebook name (e.g. "FabledSword family").
title: Rulebook name.
description: Optional short description of what this rulebook covers.
"""
uid = current_user_id()