Resolves branding configuration for report output. Triggered when the user asks to "generate a report", "create a PDF", "build a dashboard", "make a presentation", "export as Excel", "create a slide deck", or any output-generation request. Also triggered when the user asks to "set up branding", "configure brand colors", "apply brand", or "resolve branding".
Resolve branding configuration before any output generation. This skill runs first in every generation request — no generator should produce output without resolved branding.
Execute these steps in order:
Read the default brand configuration from ${CLAUDE_PLUGIN_ROOT}/skills/brand/assets/brand-config.json. This is the baseline — Acme Inc defaults with all 8 sections populated.
Check if {WORKING_DIR}/.reporting/brand-config.json exists. If it does:
colors.primary does not erase ).colors.accentTrack which fields in the firm section were explicitly set by the user — this matters for logo suppression and website rendering rules.
Check the resolved config for "nl_overrides": false. If false, skip this step entirely and log: "NL overrides disabled (nl_overrides: false)."
Otherwise, check if {WORKING_DIR}/.claude/branding.local.md exists. If it does:
Examples of NL interpretation:
colors.primary, colors.accent, etc.firm.name to "Terra Holdings"typography.font_family_heading to "Georgia, serif"This step runs AFTER NL overrides so that any NL color changes are reflected in derived tokens.
For any field in the semantic section that is not explicitly set (by defaults, JSON, or NL), derive it from the final resolved colors:
| Semantic token | Derived from |
|---|---|
heading_color | colors.primary |
body_color | colors.text |
muted_color | colors.text_secondary |
border_color | Lighten colors.text_secondary by 40% → approximate #D1D5DB |
link_color | colors.accent |
surface_alt | Lighten colors.surface by 30% |
success_bg | Lighten colors.positive to 90% lightness |
warning_bg | Lighten colors.warning to 90% lightness |
error_bg | Lighten colors.negative to 90% lightness |
chart_series | [colors.primary, colors.accent, colors.positive, colors.warning, colors.negative] |
For any field in the components section that is not explicitly set:
| Component token | Derived from |
|---|---|
table_header_bg | colors.primary |
table_header_text | colors.white |
table_alt_row | colors.surface |
Other component tokens (card_radius, card_shadow, callout_border_width, footer_height, header_height, logo_max_height) keep their defaults if not overridden.
Check for asset overrides in {WORKING_DIR}/.reporting/:
| Asset | Override path | Default |
|---|---|---|
| Primary logo | .reporting/logo.png | ${CLAUDE_PLUGIN_ROOT}/skills/brand/assets/logo.png |
| Dark logo | .reporting/logo-dark.png | ${CLAUDE_PLUGIN_ROOT}/skills/brand/assets/logo-dark.png |
| Icon | .reporting/icon.png | ${CLAUDE_PLUGIN_ROOT}/skills/brand/assets/icon.png |
| Watermark | .reporting/watermark.png | ${CLAUDE_PLUGIN_ROOT}/skills/brand/assets/watermark.png |
| Custom fonts | .reporting/fonts/*.woff2 | None (use system fonts from typography config) |
Logo suppression rule: If firm.name was overridden (via JSON or NL) but no custom logo.png exists in .reporting/, do NOT copy the default Acme logo. An overridden firm name with a mismatched logo is worse than no logo. Log: "Logo suppressed — firm.name overridden but no custom logo provided."
Website rendering rule: If firm.name was overridden but firm.website was NOT explicitly set in the user's JSON override, do not render firm.website in any output. The default Acme URL must never appear alongside a non-Acme firm name.
Delete {WORKING_DIR}/.reporting-resolved/ entirely if it exists. Never merge incrementally with a prior run — full replacement prevents stale values from persisting.
Then create .reporting-resolved/ and write:
brand-config.json — the fully resolved configuration with all 8 sections + top-level flags. Include an _office_scripts_path field set to the absolute path of ${CLAUDE_PLUGIN_ROOT}/scripts/office/ — this tells generators where to find the office utilities without copying them.brand-resolution-log.md — audit trail documenting:
logo.png, logo-dark.png, icon.png, watermark.png (or note which were suppressed).Note: office scripts (soffice.py, pack.py, unpack.py, validate.py, helpers/) are NOT copied. They are static files that live in the branding plugin at ${CLAUDE_PLUGIN_ROOT}/scripts/office/. Generators find them via the _office_scripts_path field in the resolved brand-config.json.
Report to the user what was resolved:
.reporting-resolved/All generators must follow these output rules. Include this section's rules when instructing generators.
All output goes to {WORKING_DIR}/output/ with subdirectories per format:
| Format | Output path |
|---|---|
output/pdf/ | |
| DOCX | output/docx/ |
| PPTX | output/pptx/ |
| XLSX | output/xlsx/ |
| CSV | output/csv/ |
| Markdown, HTML, TXT, JSON | output/text/ |
| Interactive apps | output/app/{app-name}/ |
Pattern: {slug}-{YYYY-MM-DD}-{HHmm}-{xxx}.{ext}
q1-performance-report.Example: quarterly-review-2026-04-04-1430-a8f.pdf
Exception: Interactive apps use descriptive directory names without timestamps (output/app/q1-dashboard/). Re-running overwrites the previous version.
Each generated file should include a meta.sources section (where the format supports it) listing the data sources used during generation.