Integration · GitHub
RampStack skills in GitHub.
Briefs as DESIGN_DIRECTION.md. Axis prefixes on Tailwind tokens and Storybook stories. PR templates that ask whether the change answers the brief.
GitHub gives the team a repository, branches, PR templates, issue templates, labels, GitHub Actions, and branch protection rules. The integration uses each one for a load-bearing role in keeping the brief present at the point code ships. The repo holds the canonical brief. The PR template is where direction adherence gets graded. Storybook stories and Tailwind tokens carry axis position into the design system code.
The shape
Brief into the repository.
DESIGN_DIRECTION.md sits at the repo root. The PR template references it. Tailwind config exposes axis-prefixed token names. Storybook stories use axis-prefixed titles. Branch protection makes the PR template required.
The mapping
Brief artifacts to GitHub primitives.
| Brief artifact | GitHub primitive | Notes |
|---|---|---|
| Brief synthesis | DESIGN_DIRECTION.md | Repo root, linked from README |
| Axis positions | Tailwind config token prefixes | tone-*, aesthetic-*, sensory-* in theme.extend |
| Axis positions (component) | Storybook story title prefixes | Tone/Professional/Buttons/Primary |
| Rejection list | CONTRIBUTING.md: Won't merge section | Plain language; the PR template links here |
| Direction grading | PR template axis checkboxes | .github/pull_request_template.md |
| Direction status | PR labels | direction:aligned, direction:drift, direction:review |
| Inspiration references | DESIGN_DIRECTION.md References section | Plain markdown links |
| Required review | Branch protection rule on main | CODEOWNERS for design-system paths |
The PR template is the load-bearing piece. Without it, the brief is documentation. With it, every change to the codebase forces a moment of brief-awareness from the author and the reviewer. The friction is the point: the moment the team starts complaining about the checkboxes, the integration is working.
Tailwind config and Storybook titles carry the axis prefix into the everyday code surface. A developer writing className=“text-tone-professional” encounters axis position at the point of writing the code. A reviewer scrolling Storybook sees axis position at the sidebar level. Both are quiet, persistent signals that the brief exists.
Templates
Copy these into the repository.
DESIGN_DIRECTION.md template
Live at the repository root. Linked from the README near the top. Linked from CONTRIBUTING.md.
# Design direction This file is the source of truth for creative direction in this repository. Every PR that touches UI, copy, or design tokens reads this file. ## Synthesis [One paragraph in present tense describing what this combination produces in practice.] ## Axes | Axis | Position | Why | | ------------ | -------------------- | ------------------ | | Tone | Professional | [one sentence] | | Aesthetic | Editorial Restrained | [one sentence] | | Relationship | Peer | [one sentence] | | Sensory | Considered | [one sentence] | ## What this brief excludes (rejection list) - [specific phrasing, structure, or visual move this brief excludes] - [next item] - [next item] ## Inspiration references - [URL] - [one sentence on what specifically resonates] - [URL] - [next reference] ## Open questions - [anything still unresolved that downstream PRs will need answered] --- For platform-agnostic patterns see [/integrations/agile-creative-direction]. For the framework see [/framework/creative-direction].
PR template (.github/pull_request_template.md)
GitHub auto-loads this template on every new PR. The Direction section is what makes the integration load-bearing instead of decorative.
## Summary
<!-- One or two sentences on what this PR changes
and why. Start with the verb. -->
## What changed
<!-- Bullet list of meaningful changes. Skip the
mechanical stuff (lockfile bumps, formatting). -->
-
-
## How to test
<!-- Steps a reviewer follows to verify the change
on their machine or in preview. -->
1.
2.
## Direction
<!-- Required for any PR that touches UI, copy, or
design tokens. Skip with N/A only if the PR is
purely backend or infrastructure. -->
This PR answers DESIGN_DIRECTION.md on the relevant
axes. Mark each row honestly:
- Tone: [ ] yes [ ] no [ ] partial [ ] N/A
- Aesthetic: [ ] yes [ ] no [ ] partial [ ] N/A
- Relationship: [ ] yes [ ] no [ ] partial [ ] N/A
- Sensory: [ ] yes [ ] no [ ] partial [ ] N/A
Rejection list check:
- [ ] I re-read CONTRIBUTING.md "Won't merge"
and confirm nothing in this PR violates it.
If anything is "no" or "partial", explain in the
comments below what would close the gap, or open
an issue tagged direction:drift.
## Screenshots
<!-- For UI changes. Before and after if applicable. -->
## Linked issues
Closes #
Relates to #Tailwind config (tailwind.config.ts)
Axis prefixes on token names. The variable picker in the editor surfaces axis position the moment a developer types className=“text-”.
import type { Config } from "tailwindcss";
export default {
content: ["./app/**/*.{ts,tsx}", "./components/**/*.{ts,tsx}"],
theme: {
extend: {
colors: {
// Tone-bound palette.
"tone-professional": {
ink: "#1c1917",
body: "#44403c",
muted: "#78716c",
accent: "#0a0a0a",
},
"tone-conversational": {
ink: "#292524",
body: "#57534e",
muted: "#a8a29e",
accent: "#047857",
},
},
spacing: {
// Aesthetic-bound spacing scale.
"aesthetic-restrained-xs": "4px",
"aesthetic-restrained-sm": "8px",
"aesthetic-restrained-md": "16px",
"aesthetic-restrained-lg": "32px",
"aesthetic-restrained-xl": "96px",
},
transitionTimingFunction: {
"sensory-considered": "cubic-bezier(0.4, 0, 0.2, 1)",
"sensory-resonant": "cubic-bezier(0.16, 1, 0.3, 1)",
},
transitionDuration: {
"sensory-considered-fast": "150ms",
"sensory-resonant-hero": "720ms",
},
},
},
plugins: [],
} satisfies Config;Storybook story naming convention
Story title is the load-bearing field. Forward-slash hierarchy turns into Storybook's sidebar tree; putting axis at the top groups the catalog by axis position automatically.
// components/Button/Button.stories.tsx
import type { Meta, StoryObj } from "@storybook/react";
import { Button } from "./Button";
const meta = {
// The title path drives Storybook's sidebar.
// Tone first because tone is the most visible axis.
title: "Tone/Professional/Buttons/Primary",
component: Button,
tags: ["autodocs"],
} satisfies Meta<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: { children: "Read more" },
};
export const Loading: Story = {
args: { children: "Read more", loading: true },
};
// In a working file, naming convention enforces
// axis visibility. Reviewers reading the catalog
// see Tone/Professional, Tone/Conversational, etc.
// at the top level.GitHub Actions workflow: direction-status label
A workflow that auto-applies a direction-status label based on whether the PR description still has unchecked axis boxes. Keeps the label in sync with the PR body without manual labeling.
# .github/workflows/direction-status.yml
name: Direction status
on:
pull_request:
types: [opened, edited, synchronize]
jobs:
label:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/github-script@v7
with:
script: |
const body = context.payload.pull_request.body || "";
const hasNo = /-\s+(Tone|Aesthetic|Relationship|Sensory):.*\[x\]\s*no/i.test(body);
const hasPartial = /-\s+(Tone|Aesthetic|Relationship|Sensory):.*\[x\]\s*partial/i.test(body);
const hasUnchecked = /-\s+(Tone|Aesthetic|Relationship|Sensory):.*\[\s\]/i.test(body);
const labels = ["direction:aligned", "direction:drift", "direction:review"];
const remove = (l) => github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
name: l,
}).catch(() => null);
await Promise.all(labels.map(remove));
let target = "direction:aligned";
if (hasNo) target = "direction:drift";
else if (hasPartial || hasUnchecked) target = "direction:review";
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
labels: [target],
});Code review checklist (CONTRIBUTING.md)
Inline this in the contributing guide. The PR template links to it under the Rejection list check.
# Reviewer checklist (UI / copy / design-token PRs)
Before approving:
- [ ] Re-read DESIGN_DIRECTION.md (synthesis +
axis positions)
- [ ] Re-read the "Won't merge" section below
For each visible change in this PR:
- [ ] The change uses axis-prefixed Tailwind tokens
(no raw hex outside theme.ts, no raw spacing
values outside the spacing scale)
- [ ] New components have a Storybook story with a
title path starting with the axis
- [ ] Copy added or changed reflects the brief's
tone position
- [ ] Motion added or changed uses the
sensory-prefixed easing/duration tokens
# Won't merge
The brief excludes the following. PRs that
introduce any of these get rejected at review:
- Three-icon feature rows on landing surfaces
- Stock-photo style hero photography
- Exclamation marks in product copy
- Generic CTA copy ("Get started", "Learn more",
"Click here")
- Skeumorphic shadows on cards or buttons
- [add the rest of the rejection list from
DESIGN_DIRECTION.md]Failure modes
Where the GitHub integration goes wrong.
DESIGN_DIRECTION.md exists but the PR template never references it. The brief becomes background reading no one opens. PRs ship without considering it. Add the brief-alignment section to the PR template; the friction is the point.
Storybook stories named without the axis convention. Stories titled Buttons/Primary instead of Tone/Professional/Buttons/Primary lose the catalog grouping. The Storybook sidebar becomes a flat list of components. Enforce the title convention via a CI check that fails when story files do not start with an axis name.
Design tokens added without an axis prefix. Someone adds a new color called “button-primary-hover” outside the tone-prefixed group. Six PRs later, the codebase has an unprefixed shadow token system. Lint the Tailwind config or fail CI on tokens that do not start with a recognized axis prefix.
Components shipped without Storybook stories. A new component lands without a story file. Reviewers cannot grade the component against the brief because they cannot find it in the catalog. Enforce via a CI check that requires a corresponding .stories.tsx for every new .tsx file under components/.
Composition
Which skills feed the GitHub integration.
The brief comes from creative-direction. The Tailwind tokens come from brand-identity. Component-level copy decisions consume brand-voice. Conversion-focused PRs consume landing-page-copy. The Figma library file is the design counterpart of the GitHub repository; both should derive from the same brief and stay in sync.
Continue reading.
For GitHub platform mechanics (PR templates, Actions, branch protection, CODEOWNERS, repository labels), GitHub's official documentation is the source of truth. The patterns above use GitHub features available on the Free plan and higher.
- Sibling
Figma integration
The design counterpart. Library tokens correspond to Tailwind tokens.
Open the page - Skill
Brand identity
The skill that produces the tokens the Tailwind config exposes.
Read the skill - Methodology
The four-axis framework
The brief format that DESIGN_DIRECTION.md mirrors.
Read the methodology - Hub
Integrations hub
The other five integration pages.
Open the hub
Frequently asked questions.
- Where does the creative-direction brief live in a GitHub repository?
- At the repository root as DESIGN_DIRECTION.md (or inside docs/ for monorepos with multiple briefs). The README points to it; the PR template references it; the contributing guide names it. The location matters less than the consistent reference path: every doc that touches design or copy decisions has to be one click from the brief.
- What does a brief-aware PR template look like?
- Standard summary, what-changed, and how-to-test sections, plus a Direction section with one checkbox per axis the change touches. Reviewers cannot click Approve until they have made an explicit yes-or-no choice on direction adherence. The friction is the point: a PR that ships UI without considering tone, aesthetic, relationship, and sensory is a PR that drifts the brief.
- How do Storybook stories surface axis position?
- Through the title path. Story titles use forward-slash hierarchy that surfaces axis at the top: Tone/Professional/Buttons/Primary instead of Buttons/Primary. The Storybook sidebar groups by axis automatically, so a designer or engineer scanning the catalog sees axis position at the navigation level and drift becomes visible at the point a new story is added.
- What is the most common GitHub-specific failure of this integration?
- DESIGN_DIRECTION.md exists in the repo but the PR template never references it. The doc accumulates as background reading no one opens, and PRs ship without considering the brief. The fix is mechanical: add the brief-alignment section to the PR template so the next PR forces every reviewer to engage with the brief or explicitly mark the change as out of scope.