Cohesion
Free Claude Code audit toolkit: accessibility, performance, SEO, privacy, design, deploy safety, codebase audits. 14 slash commands, MIT licensed.
npx -y skills add Surfrrosa/claude-skills --skill cohesionAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Visual + structural design-cohesion audit. Detects every place a page drifts from the project's design system — different button styles, missing nav/footer, hard-coded colors that should be tokens, parallel CSS classes recreating canonical components, inline `<style>` blocks redefining variables. Cross-page consistency check across the whole site, not just changed code. Use when the site looks visually inconsistent across pages, or as part of a launch-ready audit pass.
SKILL.md
22.0 KB, as published. Nobody here has run it
Cohesion Audit
Find every place a page drifts from the project's design system. The system has a canonical layer (base templates + base stylesheet + shared components + design-system docs); this skill scans everything else against that layer and reports drift, ranked by severity.
This is not a code-quality audit. It's specifically about visual + structural consistency. Different from:
- Dead-code audits (dead code / duplication)
- UX coverage audits (missing-feature gaps)
- Reuse / quality audits on changed code
- Accessibility audits
- Security review
Arguments
- No args: audit current working directory
- A project name or path (e.g.,
myapp) --live: also fetch live URLs and compare rendered output across pages--fix: auto-fix safe categories (rare; most fixes need design judgment — default off)
Project Registry
| Alias | Path | Canonical layer |
|---|---|---|
myapp | (add your projects here) | (describe your canonical files: base templates, base stylesheet, components, design system docs) |
For React Native / Expo projects: the cohesion model is different (StyleSheet objects, Theme provider, native components). Skip this skill or adapt it heavily — flag and stop.
Process
Step 0 — Identify the source of truth
Resolve the project. Read in order:
CLAUDE.md— any documented design conventions- The canonical base template(s) — typically a
base.html(Jinja),app/layout.tsx(Next.js),Layout.astro(Astro), orindex.htmlfor static sites - The canonical stylesheet — typically
base.css,globals.css, or a theme file - Any shared components / macros —
components/ui/,src/components/shared/,_macros/, etc. - Design-system docs —
DESIGN_SYSTEM.md,BRAND_VOICE.md, design contract files
From these, extract the canonical inventory:
| Token type | What to extract |
|---|---|
| Color tokens | All --* CSS variables defined in the canonical stylesheet's :root block (or Tailwind theme.colors, or equivalent) |
| Font tokens | --font-display, --font-body, etc. — and the actual font families they map to |
| Component classes | Every class defined in the canonical stylesheet that's meant to be reused: .btn-primary, .btn-secondary, .card, .form-group, .empty-state, etc. |
| Allowed base templates / layouts | Which template / layout names child pages are allowed to extend |
Allowed <link> stylesheets | Which external stylesheets are sanctioned (typically just one font provider for the canonical families) |
| Page-shell elements | What every page is expected to have: nav, footer, main landmark, lang attr, etc. |
Write this inventory down (mentally or in a scratch buffer); the audit compares against it.
Step 1 — Page-shape violations (RED)
Highest-severity drift. A page that doesn't extend the base shell shows up looking like a different site entirely.
For every page-level template / route (the ones a route handler actually renders), check:
1a. Extends an allowed base
- Jinja: does it have
{% extends "base.html" %}(or the project's canonical base)? - Next.js: is it inside the App Router root layout, or does it define its own
<html>/<body>? - Astro: does it wrap content in
<Layout>(or the project's canonical layout)? - Static HTML: does it include a canonical shared header/footer pattern?
A page that doesn't extend anything renders without nav/footer/global styles.
1b. Loads canonical stylesheet
- Does it inherit the canonical stylesheet from the base layout, OR does it load its own?
- Pages that load their own stylesheet bypass the design system.
1c. Has the canonical wordmark + nav
- If the base has a canonical
<nav>, does the page render with it? - Pages with their own custom
<nav>implementation = drift.
1d. Has the footer (specifically: includes the partial, not its own copy)
- Is the canonical footer included? Or does the page roll its own footer markup?
- Concrete detection: for every page-level template, check both:
- Does the file include the canonical footer (e.g.,
{% include "_footer.html" %}in Jinja,<Footer />in React, framework equivalent)? AND - Does the file contain a
<footer>tag NOT inside that include?
- Does the file include the canonical footer (e.g.,
- Either condition failing is RED. A page with its own inline
<footer>is the most common drift in old/orphaned pages — and when the inline copy ages, it falls behind the canonical (missing newer links like Home/Blog/social, browser-default link styling, broken indentation copy-pasted from a stale snapshot).
1e. Has the canonical background / hero layer
- If the base has a canonical background element (
.video-bg,.hero-bg, etc.), does the page rely on it or override it? - See Step 1.5 — overriding canonical background rules in page CSS is the load-bearing failure mode here.
1f. Has the canonical viewport + lang
<html lang="en">, viewport meta — usually inherited but worth checking pages with custom<head>.
Red flag heuristic: any page that defines its own <html>, <head>, <body>, or <footer> instead of inheriting from base is RED.
Step 1.5 — Global selector overrides in page CSS (RED)
The class of bug standard cohesion checks miss: a page-specific stylesheet (or inline <style> block) that redefines selectors which already exist in the canonical stylesheet. The page extends the base correctly, includes the footer correctly, but its own CSS silently overrides global rules — producing visible drift like wrong z-index on the background, wrong link colors in the footer, layout glitches in the nav.
The specific bug shape:
- Canonical stylesheet defines
.video-bg { z-index: -1 }(behind everything) - Page stylesheet redefines
.video-bg { z-index: 0 }(above default-z elements) - Browser cascade: page CSS loads after canonical, so page rule wins
- Result: the global background renders ON TOP of UI elements that don't have explicit z-index, breaking the layered visual stack
Detection (mechanical):
For every project-level .css file (NOT the canonical one):
- Extract every selector that has
display:,position:,z-index:, orfont-family:declarations - Cross-reference with the canonical stylesheet
- Any overlap is RED — even if the override "looks the same," the duplication means future canonical changes don't propagate
For every inline <style> block in a template:
4. Run the same check on its rules
5. RED if any global selectors are touched
Forbidden override list (extract from your canonical stylesheet):
For each project, the audit must build this list from the canonical layer. Common categories to extract:
- Root element selectors:
body,html - Background / shell selectors:
.video-bg,.hero-bg, etc. - Navigation: the project's nav class + any nav sub-elements
- Footer: bare
footerelement selector + any footer-specific classes - Cookie / consent banner selectors
- Skip-link selectors
- Main / landmark selectors:
main,#main-content
Each hit outside the canonical stylesheet is a RED finding. The fix is one of:
- Delete the override (let canonical drive — most common)
- Rename the selector to something page-scoped (e.g.,
.blueprint-video-overlayinstead of.video-bg) - Move the rule into the canonical stylesheet if it should apply globally
Step 1.6 — HTML well-formedness in templates (RED, mechanical)
The simplest-possible static check that catches a real class of catastrophic bugs: a page-level template has an unclosed <script> or <style> tag. The browser's HTML parser, while inside a <script> element, only exits on </script> — content type doesn't matter. So the parser stays in script-content mode through all subsequent <head> content (favicons, fonts, base stylesheet link, analytics — all swallowed as script content) until the next </script> it can find.
Detection (mechanical, per template):
# Per page-level template, count opens vs closes for tags that MUST balance.
# A mismatch is a RED finding — the page is broken HTML.
for tpl in src/templates/**/*.html; do
for tag in script style; do
opens=$(grep -cE "<$tag[[:space:]>]" "$tpl")
closes=$(grep -c "</$tag>" "$tpl")
if [ "$opens" != "$closes" ]; then
echo "RED $tpl: <$tag> $opens opens, $closes closes (mismatch)"
fi
done
done
Other tags worth balancing on page-level templates: <head>, <body>, <html>, <main>, <form>, <table>, <div> (last one is noisy — only flag mismatches > 5).
Common false-positive shape to ignore:
- Self-closing or void elements (
<meta>,<link>,<img>,<input>,<br>,<hr>) don't need closes. <script>withsrc=""is self-contained but still needs</script>per HTML spec.- Templating block boundaries inside a
<script>tag — fine, the rendered output collapses correctly UNLESS the templating block itself never closes the open<script>.
Auto-fix eligibility: balance violations are NOT generally auto-fixable — the missing close could go in many places, and inserting it wrong creates a worse bug. Always file as a follow-up with the exact line number of the unclosed open. Human inspects + adds the closing tag.
The exception: if the unclosed tag is OBVIOUSLY at the end of a templating block and the missing close is one line, an auto-fix is safe.
Step 1.7 — Shared UI-component class drift (RED)
The most insidious drift category — what we'll call parallel-definition drift:
- A canonical class like
.form-section-titleis defined inbase.csswithcolor: var(--secondary)(copper) - The SAME class is redefined in several page-level CSS files, all with subtly different colors
- A user notices visible drift across forms: section headers reading as a different shade than field labels
- Fix requires updating all definitions in lockstep AND patching files that USED the class but didn't define it (relying on browser defaults)
This is distinct from Step 3's component drift:
- Step 3 catches: page invents
.checkout-btninstead of using canonical.btn-primary(USAGE drift) - Step 1.7 catches: page redefines
.btn-primaryitself with different properties (DEFINITION drift)
Definition drift is worse because each copy is a subtle variation of the canonical; updating the canonical doesn't propagate. The user perceives it as "100 different shades of white" or "buttons that almost-but-don't match." Standard cohesion checks miss it because each individual rule looks valid in isolation.
Canonical UI-component class list (extract from your canonical stylesheet):
For each project, build this from the actual stylesheet. Common patterns:
- Form scaffolding:
.form-section-title,.form-section,.form-group,.field-label,.field-error,.field-help - Buttons:
.btn,.btn-primary,.btn-secondary,.btn-text - Cards:
.card,.card-* - States:
.empty-state,.error-state - Layout:
.skip-link,.video-bg,.sticky-nav,.nav-*
For each class, run three mechanical checks:
1.7a — Duplicate definitions (RED)
# For each canonical class, count definitions across the project:
for cls in form-section-title field-label btn-primary btn-secondary card empty-state; do
hits=$(rg -ln "^\\s*\\.${cls}\\s*\\{" src/)
count=$(echo "$hits" | grep -c .)
if [ "$count" -gt 1 ]; then
echo "RED .${cls} defined in $count files:"
echo "$hits" | sed 's/^/ - /'
fi
done
A canonical class should be defined ONCE, in your canonical stylesheet. Page-level redefinitions are RED, even if the values look identical — the duplication itself is the bug.
1.7b — Property-value mismatch across definitions (RED)
When a class IS defined in multiple places, compare property values:
# Pull every definition + its property block, diff against the canonical:
rg -A 15 "^\\s*\\.form-section-title\\s*\\{" src/
# → eyeball: do `color`, `font-family`, `font-size`, `padding`, `letter-spacing`
# match across all hits? Mismatches are RED.
Especially flag: color, font-family, font-size, font-weight, padding, letter-spacing, border. These produce the most visible cross-page drift.
1.7c — Used-but-undefined (RED)
A class used in markup with NO matching CSS rule reachable on the page renders with browser defaults — silently broken until someone notices.
# For each canonical class, find templates that USE it:
for cls in form-section-title field-label btn-primary card; do
rg -l "class=\"[^\"]*\\b${cls}\\b" src/templates/ | while read tpl; do
# Check if the template loads a stylesheet that defines the class.
# Simplest heuristic: does the canonical stylesheet load on this page
# AND does it define the class?
base_loads=$(grep -l "extends.*base.html\|/static/base.css" "$tpl")
base_defines=$(grep -c "^\\s*\\.${cls}\\s*\\{" src/static/base.css)
if [ -z "$base_loads" ] && [ "$base_defines" -gt 0 ]; then
echo "RED $tpl uses .${cls} but doesn't load base.css"
fi
done
done
Auto-fix bundle (per Step 7 pattern):
- 1.7a duplicates with verbatim copy → bundle PR that deletes the duplicates, leaves only the canonical
- 1.7b property mismatch on a single property (e.g., just
color) → bundle PR that flips all definitions to the canonical value - 1.7b property mismatch on multiple properties → file as follow-up, needs design judgment
- 1.7c orphan usage → file as follow-up; either add to canonical stylesheet or stop using
Step 2 — Token discipline (YELLOW)
Find every place that hard-codes a value that should be a token. These look fine in isolation but produce subtle drift over time.
2a. Hex color codes outside the canonical stylesheet
- Grep for
#[0-9a-fA-F]{3,6}across all templates + static files. - Filter out the canonical stylesheet itself + any acceptable surfaces (e.g., favicon manifest, social-card images).
- Every remaining hit is a candidate for tokenization. Cross-reference: does the hex match an existing token? If yes, it's a swap-in fix. If no, it's a new color the design system should know about.
2b. font-family: declarations outside the canonical stylesheet
- Inline
style="font-family: ..."and page-specific<style>blocks redefining font-family.
2c. Inline style attributes that redefine tokens
style="color: #B87333"should bestyle="color: var(--accent)"(or better, a class)style="background: rgba(26, 20, 24, 0.6)"should be a token
2d. External font imports beyond the canonical set
- Drift here is silent and brand-breaking.
Step 3 — Component drift (YELLOW)
Find every place that recreates a canonical component instead of using the macro/class.
3a. Button-like elements not using .btn-* classes
- Every
<button class="...">and<a class="...">whose visual is button-like - Group by class. If the same visual exists under 5 different class names, that's drift to consolidate.
- Especially flag: page-scoped classes like
.checkout-btn,.sample-report-link,.primary-actionthat recreate.btn-primarystyling.
3b. Card-like <div> clusters that should be the canonical card component
- Look for
<div class="*-card *-panel *-box">patterns with manual border + padding + border-radius - These should use the project's canonical card primitive.
3c. Form inputs that bypass the canonical form scaffolding
- Any
<div class="form-group"><label><input></div>markup that exactly mirrors what the canonical form macro renders should be migrated to the macro.
3d. Status/empty/error states bypassing the canonical state component
- Custom "no results" markup, custom error banners — fold into the canonical component.
Step 4 — Inline <style> block size (smell heuristic)
For each page template:
- Count lines inside
<style>blocks (excluding comments and whitespace) - A page with > ~50 lines of inline CSS is probably drifting from the system
- Rank pages by inline-CSS size; the worst offenders get top billing in the report
This isn't a violation per se — sometimes page-specific styling is correct. But it's a smell. Worth eyeballing the largest blocks for token drift, parallel components, or stuff that should be in the canonical stylesheet.
Step 5 — Cross-page rendering compare (--live flag)
When --live is passed, fetch every public route via WebFetch and parse the rendered HTML.
For each page, check the rendered output (not source) for:
<main>landmark present- Canonical
<nav>present <footer>present- Canonical background element present
- Canonical font preconnects + font provider link present
- No additional
<link rel="stylesheet">beyond the canonical set <html lang="...">present
Build a comparison matrix:
| Page | nav | footer | bg | base.css | extra stylesheets |
|---|---|---|---|---|---|
/ | yes | PASS | yes | PASS | (none) |
/blog | yes | PASS | yes | PASS | (none) |
/checkout | yes | no (custom) | yes | PASS | own.css |
| ... |
Pages with any "no" are RED. Inconsistencies across the matrix are the visible drift.
Step 6 — Ranking
Compose findings into a single prioritized report:
## Cohesion Audit — [project]
### RED RED — Page-shape violations
1. **[file]** — extends base but overrides the content block with full custom layout including its own nav and footer. Drift visible to users.
2. **[file]** — does not extend any base; renders with bespoke `<head>`/`<body>`. Carries its own @font-face block + footer.
### YELLOW YELLOW — Component drift
1. `.checkout-btn` recreates `.btn-primary` (used in [N] places). Migrate or alias.
2. `.sample-report-link` recreates `.btn-text`. Migrate.
3. [N] inline `style="color: #B87333"` should be `var(--accent)`.
### YELLOW YELLOW — Token discipline
1. [N] hex colors outside canonical stylesheet ([list top 5 with file:line]).
2. [N] `font-family:` declarations outside canonical stylesheet.
### ORANGE SMELL — Inline `<style>` block size
1. `tools/blueprint.html` — [N] lines of inline CSS (largest)
2. `tools/time-travel.html` — [N] lines
3. `pages/index.html` — [N] lines (may be acceptable; landing pages tend to have hero-specific styling)
### Summary
- Top priority: [the worst offender]
- Next: [the next 2-3 priorities]
- Estimated cleanup effort: [rough size]
Each RED finding gets a follow-up issue or note (or one umbrella issue with sub-findings) per project conventions.
Fix Mode (--fix flag) and auto-fix bundle
When --fix is set, bundle the auto-fixable findings into a single PR.
Safe to auto-fix (auto_fix: true):
- Replace inline
<footer>block with the canonical footer include when the inline copy is a stale partial of the canonical footer - Delete page-CSS rules that override global selectors when the override doesn't add new behavior. If the override DOES change behavior, downgrade to
auto_fix: false(needs design review). - Replace inline
style="color: #B87333"withstyle="color: var(--accent)"when the hex unambiguously matches a known token - Add
rel="stylesheet"reference to the canonical stylesheet on a page that doesn't load it (only if the page already extends a base — bare-<head>rewrites are NOT auto-fixable) - Remove dead CSS rules (e.g., orphan selectors with no markup using them)
Requires confirmation (auto_fix: false):
- Migrating a page from custom layout to extending the canonical base (changes routing assumptions, may break tests)
- Replacing a parallel button class with
.btn-primary(may need CSS specificity adjustments + visual review) - Removing an inline
<style>block in favor of canonical equivalents (extraction first, then cleanup as separate PR) - Renaming a global-selector override to a page-scoped class (touches markup + CSS together)
Never auto-fix:
- Hex colors that don't match a known token (could be intentional brand exception or a new token to add)
- Font-family changes (could break ascenders/descenders/em sizing)
- Removing custom layouts (usually represents real design judgment that needs review)
- Page-CSS that overrides a global selector if the override is non-trivial (e.g., adds keyframes, redefines a media query block) — flag and file as follow-up, don't touch
Workflow: partition findings by auto_fix, build branch + commit + push + open PR with the auto-fixable set, file follow-ups for the rest. Cap at 5 fixes per PR; if more, split by category (footer-includes, override-deletions, hex-substitutions, etc.).
Rules
- Source of truth is the canonical layer. Don't invent a "what should be" from thin air; read the base layout, base stylesheet, components, and design docs to compute the inventory FIRST. Then audit against THAT.
- Severity by impact. A page without the global nav is RED — users see a different site. A hex color that should be a token is YELLOW — invisible drift today, brand-breaking when the brand color changes tomorrow.
- Per-token-substitution fixes are easy; layout migrations are hard. Default scope is detection + reporting. Layout migrations need a separate ticket per page.
- Watch for grandfathered violations. Existing cohesion lints often have an explicit grandfathered list. Read it; don't re-flag what's already known. Do flag if items have been on the list too long.
- Be specific. "tools/blueprint.html drifts from the design system" is useless. "tools/blueprint.html declares its own @font-face for Cormorant Garamond at line 47, has a 480-line inline
<style>block, uses.checkout-btninstead of.btn-primary, and includes a custom<footer>instead of the canonical footer include" is useful.
Skill Run Logging
If you keep a skill-run log, append an entry after each run:
Format: | YYYY-MM-DD | /cohesion | target (details) | one-line result |