agentsclimarketplace

Cohesion

Skill Surfrrosa/claude-skills/cohesion

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.From its SKILL.md

Install
npx -y skills add Surfrrosa/claude-skills --skill cohesion

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things 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.
  • runs commandsInstructs the agent to run 3 commands, including `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:` and 2 more.

SKILL.md

22.0 KB, ~5.2k tokens by cl100k_base, 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

AliasPathCanonical 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:

  1. CLAUDE.md — any documented design conventions
  2. The canonical base template(s) — typically a base.html (Jinja), app/layout.tsx (Next.js), Layout.astro (Astro), or index.html for static sites
  3. The canonical stylesheet — typically base.css, globals.css, or a theme file
  4. Any shared components / macros — components/ui/, src/components/shared/, _macros/, etc.
  5. Design-system docs — DESIGN_SYSTEM.md, BRAND_VOICE.md, design contract files

From these, extract the canonical inventory:

Token typeWhat to extract
Color tokensAll --* 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 classesEvery 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 / layoutsWhich template / layout names child pages are allowed to extend
Allowed <link> stylesheetsWhich external stylesheets are sanctioned (typically just one font provider for the canonical families)
Page-shell elementsWhat 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?
  • 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):

  1. Extract every selector that has display:, position:, z-index:, or font-family: declarations
  2. Cross-reference with the canonical stylesheet
  3. 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 footer element 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-overlay instead 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> with src="" 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-title is defined in base.css with color: 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-btn instead of using canonical .btn-primary (USAGE drift)
  • Step 1.7 catches: page redefines .btn-primary itself 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 be style="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-action that recreate .btn-primary styling.

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:

Pagenavfooterbgbase.cssextra stylesheets
/yesPASSyesPASS(none)
/blogyesPASSyesPASS(none)
/checkoutyesno (custom)yesPASSown.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" with style="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-btn instead 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 |

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.