feat(design-systems): give a design system a way to reach the session
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 28s
CI & Build / TypeScript typecheck (push) Successful in 37s
CI & Build / Python tests (push) Successful in 51s
CI & Build / Build & push image (push) Successful in 31s

Storing a design system never made a session aware of one. Rules get pushed
into every session by the SessionStart hook and returned by enter_project; a
design system had neither, so its standards were reachable only by an agent
that already knew to call resolve_design_system — the same silent failure as a
token nobody declares.

That gap was invisible while the operator's visual standards also lived in a
rulebook. Retiring that rulebook (which is what this unblocks) would have
deleted design guidance from every session with nothing to say so.

- services/design_systems.design_context() — the delivery side. Guidance is
  chain-merged ANCESTOR-FIRST: a child system holds only what it CHANGES, so
  its own guidance describes a departure from a house style it never restates,
  and the leaf alone is a fragment. Tokens are summarised (count + group
  names), not listed — a hundred declarations would crowd out the context they
  are meant to inform.
- enter_project returns `design_system`, null when the project has none.
- The SessionStart context gains a Design system block with pointers to the
  values, alongside the always-on rules.
- server.py's entity list gains Design system, including the negative: do NOT
  record one as a rulebook, because a token kept as prose cannot be resolved,
  inherited, rendered or checked.
- The rulebook-tier passage used "a design-system rulebook" as its worked
  example of a subscribed rulebook — it now teaches the opposite, plus a new
  "is this a rule at all?" test pointing at design systems, processes and
  snippets.
- using-scribe gains a section on building UI against the project's system.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs
This commit is contained in:
2026-07-31 22:10:09 -04:00
co-authored by Claude Opus 5
parent 1e139d0d18
commit 731ca284c3
8 changed files with 356 additions and 6 deletions
+23 -2
View File
@@ -42,6 +42,18 @@ What each part is for, and when to reach for it:
- Note: durable free-form knowledge — reference material, decisions, logs of
what happened.
No lifecycle, not actionable. Reach for one to CAPTURE something worth keeping.
- Design system: the visual standards a project's UI is built from — design
tokens (name + value per mode) plus the prose a token table cannot hold
(aesthetic, voice, what is out of scope). Systems INHERIT: a child holds only
what it changes and the chain supplies the rest, so a family's house style and
one app's departures from it are the same structure at two depths. A project
points at one with set_project_design_system, and enter_project then hands it
back with the guidance chain-merged. Treat it as binding for UI work: reach
for a token (resolve_design_system / get_design_system_stylesheet) before
writing a colour, size, radius or duration by hand. Do NOT record a design
system as a rulebook — rules are for behaviour, and tokens kept as prose
cannot be resolved, inherited, rendered to a stylesheet, or checked against
code.
- System: a per-project, reusable, self-describing subsystem/area. Associate any
record (note, task, issue) with it via system_ids so research, build-work, and
fixes for the same area line up, and recurring problem-spots surface. Manage
@@ -144,8 +156,8 @@ right altitude:
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).
(e.g. a code-review checklist, or a compliance regime a category of
projects shares — 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
@@ -153,6 +165,15 @@ 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.
Before writing a rule, check whether another entity already models the thing.
A rule is prose an agent must remember and apply; the other entities are
structure a tool can resolve, render and check. Visual standards are a DESIGN
SYSTEM, not a rulebook — a token can be inherited, resolved per mode, rendered
to a stylesheet and diffed against code, and none of that survives being
written as a rule. A repeatable procedure is a PROCESS. Reusable code is a
SNIPPET. Reach for a rule when the thing genuinely is a standing instruction
about how to work, and nothing else can hold it.
One thing NOT to do: don't bridge Scribe into a session by writing to the
host's native memory. Rules are pull-only, so a fresh session won't reach for
them unless its always-loaded context says to — but the bridge for that is the
+16 -1
View File
@@ -17,6 +17,7 @@ keeps working.
from __future__ import annotations
from scribe.mcp._context import current_user_id
from scribe.services import design_systems as design_systems_svc
from scribe.services import milestones as milestones_svc
from scribe.services import notes as notes_svc
from scribe.services import projects as projects_svc
@@ -53,7 +54,13 @@ async def enter_project(project_id: int) -> dict:
Returns a dict with keys: project, milestone_summary, applicable_rules,
project_rules, subscribed_rulebooks, applicable_rules_truncated,
open_tasks, recent_notes.
open_tasks, recent_notes, design_system.
`design_system` is null unless the project points at one. When present it
carries the chain-merged guidance (the house style AND this project's
departures from it) plus a summary of the token set — treat it as binding
for any UI you write, and pull the values with resolve_design_system or
get_design_system_stylesheet before reaching for a literal.
"""
uid = current_user_id()
project = await projects_svc.get_project(uid, project_id)
@@ -74,9 +81,17 @@ async def enter_project(project_id: int) -> dict:
uid, is_task=False, project_id=project_id,
sort="updated_at", limit=5,
)
# A project need not have one, and most installs won't — null is ordinary
# here, not a missing prerequisite.
design_system = None
if project.design_system_id:
design_system = await design_systems_svc.design_context(
uid, project.design_system_id,
)
return {
"project": project.to_dict(),
"design_system": design_system,
"milestone_summary": milestone_summary,
"applicable_rules": applicable["rules"],
"project_rules": applicable.get("project_rules", []),