brand: a per-project skin for cards and reports
Output = a small committable .readable/ dir at the project root (ONLY at a project root, never ~/.claude or $HOME: config dirs are not projects). From then on /report reskins automatically, and chat cards do too (the session hook announces the dir at session start; an app restart lets other sessions pick up a brand created mid-session). Since 4.13.1 the card server never guesses a brand across open projects: a call without an announced brand renders stock, so parallel branded projects cannot leak into each other.
1. Detect before asking
Search the repo for an existing identity, in this order; quote what you find to the user before generating:
- Design tokens:
**/tokens.css,**/design-system/**, CSS custom props in the main stylesheet,tailwind.config.*color scales. DESIGN.md/BRAND.md/ brand guidelines docs.- Logos:
media/brand/,public/*.svg, favicon SVGs. Prefer a mark that usescurrentColor(theme-flips for free). - Fonts:
@font-facefiles in the repo, or the families the site loads.
If ≥ a primary/accent color and a light-or-dark character are found, generate directly. Otherwise interview with AskUserQuestion, ONE batch: accent color (offer 3 sensible hues + custom hex), light surface character (pure white / warm cream / cool gray), dark base (ink navy / graphite / near-black), wordmark text + optional logo path, one tone word (serious/friendly/technical — store it, it guides future doc copy). Never ask what detection already answered.
2. Generate .readable/
brand.css — variable overrides only, in EXACTLY this vocabulary (card template + report shell both consume it). Author card-first: a :root{} light block and a bare [data-theme="dark"]{} dark block (consumers normalize selectors themselves). Vars: --text-primary --text-secondary --text-accent --surface-1 --surface-2 --border --border-strong --bg-success --bg-accent --bg-warning --bg-danger --font-mono (report-only extra: --page-bg). Chart hues go on .rc{--ca:… --cb:… --cc:… --cd:…} (dark tweaks via [data-theme="dark"] .rc{…}).
Rules of taste: derive the full ramp from the 1-2 given colors — tinted, not gray, surfaces; --bg-accent = a soft wash of the accent; keep --text-accent ≥ 4.5:1 contrast on --surface-1 in BOTH themes (compute it, don't eyeball); dark theme is a designed palette, not inverted light. A Google-Fonts family may be declared via brand.json; never @import other hosts (cards strip them).
brand.json (optional but recommended):
{ "name": "پایا", "wordmark": "پایا", "kind": "سند داخلی تیم",
"logo": "logo.svg", "tone": "صنعتی، ساده",
"font": { "family": "Vazirmatn", "google": "Vazirmatn:wght@400;500;700",
"files": { "400": "fonts/X-Regular.woff2", "700": "fonts/X-Bold.woff2" } } }
wordmark/kind/logo feed the letterhead: the report header, and since 4.14.0 a matching .brand row mounted above chat cards too (logo + wordmark + kind, fetched by the bridge through read_brand_head). font.files are inlined into reports; font.google is the only font path that also reaches chat cards.
"signature": false (5.2.0) drops readable's own one-line credit from this project's cards and reports. It is ON by default everywhere, including branded projects. Offer it when the project's reports go to CLIENTS: a branded report is the client's document, and a toolmaker's mark under someone else's letterhead reads as a subcontractor watermark. Internal or public-facing projects should keep it. One flag covers both paths (the card server and build.py read the same key), and it is committable, so the whole team gets the same answer.
logo.svg — copy the project mark VERBATIM (no redesign), ≤ 8KB, currentColor preferred.
3. Prove it, then hand over
- Build a sample report through the report skill's
build.pywith a 5-block fragment; verify in a browser: both themes, palette applied, header shows, accent contrast holds. - Render one chat card passing
brand: "<abs>/.readable", then keep passing it on EVERY card for the rest of this session (the hook only announces at session start, so a just-created brand is otherwise invisible until restart). A pre-4.13 card server ignores the param harmlessly; tell the user other sessions start branding after an app restart. - Tell the user to commit
.readable/(it is team-shared config, not local state).