Skip to content

Inject DESIGN.md Context

Goal: load a project’s committed visual identity (its DESIGN.md) plus the format’s lint rules into agent context, so UI work stays on-brand without re-deriving the design system each session. Concepts and the decisions behind this surface live in the DESIGN.md explanation.

  • The project has a committed DESIGN.md at its root (or you want the clean no-op guidance for adopting one).
  • The design-md-context registry skill is provisioned to the project (cdprov add skill design-md-context), or you invoke the script directly.
  • jq; network for the first npx fetch of the pinned CLI (offline runs degrade gracefully — see below).

Provisioned projects load the skill automatically; ask for the design system (“load the design tokens”, “apply the design system”) or run the script as the skill instructs. The skill treats the emitted envelope as authoritative design context for all subsequent UI generation.

The script is a plain executable with no session dependency — there is no global bin/ entrypoint because the skill is provisioned per-project (web apps only), while bin/ is reserved for universal tooling:

Terminal window
~/.claude/registry/skills/design-md-context/scripts/design-context.sh /path/to/project

A project with this DESIGN.md at its root:

---
name: Heritage
colors:
primary: "#1A1C1E"
neutral: "#F7F5F2"
typography:
body-md:
fontFamily: Public Sans
fontSize: 1rem
rounded:
md: 8px
spacing:
md: 16px
---
## Overview
Architectural minimalism — deep ink on warm limestone.

Running the script:

Terminal window
$ ~/.claude/registry/skills/design-md-context/scripts/design-context.sh ~/projects/heritage-site
{
"present": true,
"path": "/Users/you/projects/heritage-site/DESIGN.md",
"design_md": "---\nname: Heritage\ncolors:\n primary: \"#1A1C1E\"\n ...",
"rules": {
"rules": [
{ "name": "broken-ref", "severity": "error", "description": "Broken/circular references and unknown component sub-tokens." },
{ "name": "contrast-ratio", "severity": "warning", "description": "WCAG contrast ratio — warns when component backgroundColor/textColor pairs fall below the AA minimum of 4.5:1." }
]
},
"rules_source": "spec-rules-only",
"cli": "@google/design.md@0.3.0"
}

design_md is the verbatim file — inject tokens and prose. rules is what the lint gate (#903) will enforce, so the agent designs within the rules rather than discovering them at commit time.

On a project without a DESIGN.md:

Terminal window
$ ~/.claude/registry/skills/design-md-context/scripts/design-context.sh /tmp/some-cli-repo
{
"present": false,
"root": "/tmp/some-cli-repo",
"guidance": "No DESIGN.md at the project root. To adopt one: author it by hand (YAML front-matter tokens + prose rationale), extract it from existing code, or generate it upstream via Google Stitch. See docs/explanation/design-md.md in the BoB source repo."
}

Exit code is 0 in both cases — absence is a legitimate state, not an error.

Condition Behavior
No DESIGN.md present: false + adoption guidance, exit 0.
npx unreachable (offline) Envelope still emitted; rules: null, rules_source: "unavailable"; the skill’s built-in format essentials cover the gap.
Missing jq Hard error, exit 1 — the only real failure mode.

Output is deterministic for a given DESIGN.md — no timestamps, safe to cache and diff.

The same skill ships a lint gate with two wirings — session hook and CI check — both delegating to scripts/design-lint-check.sh (exit 0 pass or no-DESIGN.md no-op, 1 findings at threshold, 2 environment failure).

Add to the project’s .claude/settings.json. The command is bare — the hook reads stdin JSON per the BoB hook convention:

{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "~/.claude/registry/skills/design-md-context/hooks/design-md-lint-hook.sh"
}
]
}
]
}
}

Edits to any other file pass silently; a DESIGN.md edit that fails lint feeds the findings straight back to the agent (exit-2 stderr), so broken token references or WCAG contrast failures are fixed in the same turn they are introduced.

Run the check script as a CI step (or a checks entry in dev.json so warp-drive’s check-runner picks it up):

.github/workflows/ci.yml
- name: DESIGN.md lint
run: ~/.claude/registry/skills/design-md-context/scripts/design-lint-check.sh . --fail-on warning
dev.json
{ "checks": [ { "name": "design-md-lint", "kind": "lint",
"command": "~/.claude/registry/skills/design-md-context/scripts/design-lint-check.sh ." } ] }

Findings are structured JSON on stdout (severity, path, message, summary counts), so downstream tooling parses results instead of scraping text.

Windows: the CLI binary design.md breaks Windows cmd shims, so upstream also ships a designmd alias. Both wirings invoke the package pin via npx @google/design.md@0.3.0, which resolves the correct per-platform shim — no OS branching needed in project config.

Enable the diff check (PR regression gate)

Section titled “Enable the diff check (PR regression gate)”

scripts/design-diff-check.sh diffs the base-branch DESIGN.md against the head and fails on regression — wire it as a PR check:

# .github/workflows/ci.yml — PRs need the base ref available
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- name: DESIGN.md diff gate
run: ~/.claude/registry/skills/design-md-context/scripts/design-diff-check.sh . --gate removed

Pick the gate by how strict the design system is:

--gate Fails when Use for
removed (default) A token is removed or the file deleted Most projects — additive change stays cheap.
modified Removed or any token value changed Locked-down brand systems.
any Any token change, including additions Systems where every token change needs design sign-off.
none Never (advisory) Annotate-only: parse the JSON and comment on the PR.

A DESIGN.md that is new in the branch passes (nothing to regress against); one deleted in the branch fails any non-advisory gate. --base <ref> overrides the default merge-base comparison.

design.md export derives build-ready token artifacts from the committed DESIGN.mdit owns the token→Tailwind path wherever a DESIGN.md exists. (scaffold-tokens.sh from the design-systems skill remains only for projects with a standalone tokens.json and no DESIGN.md — never run both, per the reconciliation.)

--format Output Consumer
css-tailwind Tailwind v4 CSS @theme block of custom properties Tailwind v4 projects — import the CSS.
json-tailwind (alias tailwind) Tailwind v3 theme.extend JSON Tailwind v3 tailwind.config.js.
dtcg W3C Design Tokens (2025.10 schema) tokens.json Style Dictionary, Figma token plugins, any DTCG-aware pipeline.

Generating the Tailwind v4 theme for the Heritage project from the earlier example, committed as a derived artifact:

Terminal window
$ cd ~/projects/heritage-site
$ npx @google/design.md@0.3.0 export DESIGN.md --format css-tailwind > src/styles/design-tokens.css
$ cat src/styles/design-tokens.css
@theme {
--color-primary: #1a1c1e;
--color-neutral: #f7f5f2;
--font-body-md: "Public Sans";
--text-body-md: 1rem;
--radius-md: 8px;
--spacing-md: 16px;
}

The same source emits a Tailwind v3 config fragment —

Terminal window
$ npx @google/design.md@0.3.0 export DESIGN.md --format json-tailwind
{
"theme": {
"extend": {
"colors": { "primary": "#1a1c1e", "neutral": "#f7f5f2" },
"fontFamily": { "body-md": ["Public Sans"] },
...
}
}
}

— or a DTCG tokens.json (--format dtcg) for design-tool pipelines. Re-export in CI after any DESIGN.md change (or in the same commit), so the derived artifacts never drift from the owned source.