tableau-brand
Step 4 of 8. Turns the analyst's branding into a DESIGN-TOKENS.md — the single
source of truth for palette, type, and spacing that tableau-mock (the HTML
demo) and tableau-build (the .twb) both consume.
| Reads | The analyst's branding/ (lowercase input): branding/branding.md (spec, preferred), an org template branding/*.twb, and any branding/logo.* / branding/icons/. Falls back to the scaffold/branding/EXAMPLE-branding.md demo. No required read — branding is an input, so this step never refuses for a "missing" file (CONTRACT.md §1). |
| Writes | DESIGN-TOKENS.md at the project root (latest approved truth; overwritten in place). May also author branding/branding.md from a scraped .twb or the brand interview. |
| STATE.md update | Sets brand = approved (tokens authored) or skipped; flips every downstream approved step to stale on a re-run (CONTRACT.md §4.2). |
| Entry gate | Refuses to run until init is approved in STATE.md (CONTRACT.md §4.1). |
| Next step | tableau-plan (or tableau-route to confirm). |
Tell the analyst this step matters. Branding is what lets the later steps know how to build the mock and how to write a precise Tableau implementation spec. Don't skimp on the palette, the fonts, the padding, the sizing — vague branding here produces a bland, generic dashboard downstream. This is why the step can only be skipped once
branding/branding.mdexists (see below): the analyst must capture at least some brand intent before opting into neutral styling.
The mechanical guarantees — the entry gate, the DESIGN-TOKENS.md schema check, the
skip precondition, and the STATE.md transition — live in brand.py, this skill's
executable mirror of the contract. Your job is the part that needs judgment: reading
the branding (or interviewing for it) and authoring the tokens. Run the script at the
two points below; do not hand-edit STATE.md yourself.
How to run
Precheck. From the project directory, run:
python "${CLAUDE_PLUGIN_ROOT}/skills/tableau-brand/scripts/brand.py" precheck "<project-dir>"(Use
python3ifpythonis unavailable.) If it prints[BLOCKED], relay the reason and stop — the analyst must runtableau-initfirst. Otherwise note its signals: whether aDESIGN-TOKENS.mdalready exists (refine vs overwrite), the source mode, any logo/icon assets to integrate, and whether skip is allowed.Refine vs overwrite. If precheck reports
DESIGN-TOKENS.mdalready exists, use AskUserQuestion to offer Refine (keep its structure, update values), Overwrite (author fresh), or Skip (only if allowed). Never silently overwrite existing tokens.Follow the source mode precheck reported:
source mode what to do specExtract tokens from branding/branding.md.spec+twbScrape the org branding/*.twband use it to enrich the existingbranding/branding.md(don't discard the analyst's spec), then build tokens.twbScrape the org branding/*.twb, writebranding/branding.mdfrom what you find, then build tokens.scaffoldOnly the scaffold/demo example exists — say so (you're demoing, not using real brand input).noneRun the brand interview (next section), write branding/branding.mdfrom the answers, then build tokens.When a
.twbis involved: before reading it, ask the analyst to confirm the workbook is as thin as possible (a minimal template — ideally one styled sheet/dashboard, no large data extracts or dozens of sheets). A heavy.twbfloods the context with irrelevant XML. Scrape only what feeds design tokens: fonts, colors (fills, text, series palette), sizing, container/spacing structure, and any embedded logo (<zone type='bitmap'>).Brand interview (source mode
noneonly). When there is no branding input at all, do not leave the brand blank — interview the analyst, borrowing thegrill-meapproach but bounded to at most 10 questions. Ask one at a time, propose a recommended default for each (fromreferences/tableau-design-tokens.md), and choose the questions that recover the most token-relevant information: primary/secondary colors, a cohesive ≤5-color series palette, font family (default the Tableau family), title vs label sizing, card padding / section spacing, dashboard sizing mode, and whether a logo/icons exist. Prefer AskUserQuestion (multiple-choice with your recommendation first). Write the answers intobranding/branding.md, then build tokens.Author
DESIGN-TOKENS.md. Write (orEdit, when refining)DESIGN-TOKENS.mdat the project root usingreferences/DESIGN-TOKENS-TEMPLATE.mdas the structure. Fill palette/type/spacing from the branding source. For every value the brand did not specify, pull the Tableau default fromreferences/tableau-design-tokens.mdand list it under## Fallback Decisions— that section is how the analyst sees which visual choices were guessed (it is required; if nothing was guessed, write "None"). Integrate any logo/icons precheck found. Present the tokens for approval.Commit — only after the analyst approves (or chooses to skip):
python "${CLAUDE_PLUGIN_ROOT}/skills/tableau-brand/scripts/brand.py" commit "<project-dir>" --status approved # or, to skip the step (allowed only once branding/branding.md exists): python "${CLAUDE_PLUGIN_ROOT}/skills/tableau-brand/scripts/brand.py" commit "<project-dir>" --status skippedOn
--status approvedthe script validatesDESIGN-TOKENS.mdhas the required core; if it prints[REFUSED]listing missing sections, add them and re-run. On--status skippedit refuses unlessbranding/branding.mdexists. On success it records the status and reports any downstream steps it markedstale. Relay the summary and tell the analyst to open a fresh conversation and run the next step (tableau-plan, ortableau-routeto confirm).
The DESIGN-TOKENS schema
brand.py enforces the required core; the rest is recommended-but-optional.
| section | required? | what goes there |
|---|---|---|
## Colors |
required | Backgrounds, accent bars, a cohesive ≤5-color series palette, text colors. |
## Typography |
required | Font family + sizes/weights for title, chart title, labels, tooltips. Font family is a machine value - tableau-build copies it into every text run's fontname=, so it must be one installed family, weight included: Tableau Bold | Tableau Book | Tableau Light | Tableau Medium | Tableau Regular | Tableau Semibold. There is no font called plain Tableau; keep availability notes in prose, not in the value. |
## Spacing |
required | Card padding, section spacing, container margins, accent-bar height. |
## Fallback Decisions |
required | Every value pulled from a Tableau default, flagged as guessed (or "None"). |
## Source |
optional | Which branding source produced these tokens. |
## Dashboard Sizing |
optional | Mode (default Range), min width/height, max (default Flex). |
## Logo / ## Icons |
optional | Brand assets to integrate; omit when none. |
The validator matches headings as case-insensitive substrings and allows extra custom sections, so a refined token file that keeps its own structure still passes.
Notes
- Skippable, but deliberately gated. Skipping records
skippedinSTATE.mdand yields neutral styling downstream (mock/buildreadDESIGN-TOKENS.mdas an optional input — absent ⇒ neutral, CONTRACT.md §1). But skip is only offered oncebranding/branding.mdexists, so the analyst can't bypass branding with zero brand intent on file. - Defaults worth keeping (from
references/tableau-design-tokens.md): the native Tableau font family (Bold/Medium/Light); a cohesive ≤5-color palette (a dashboard speaks one color language); Range sizing with no max (Flex), not Automatic; worksheet headers hidden with the visible title as a Text object; a collapsible filter panel via a Show/Hide button. - Root file, no version bump. Re-running refines the root
DESIGN-TOKENS.mdin place and flips downstreamapprovedsteps tostale; it does not create a new version directory (DESIGN-TOKENS.mdis a root "latest truth" file, CONTRACT.md §4.3).
The full
STATE.mdschema and the ordering / staleness / versioning rules live inCONTRACT.mdat the repo root. This skill restates only its own slice;brand.pyis the executable mirror of the contract it enforces.