craft-site — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited craft-site (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Atomic design system patterns for Craft CMS 5 site templates. Vanilla Twig — no module dependency. Works with any Craft 5 project.
This skill is scoped to front-end template architecture — component design, routing, composition, theming, and buildchain. For extending Craft (plugins, modules, PHP), see the craftcms skill.
When this skill triggers, also load:
craft-cloud.yaml at the repo root or craftcms/cloud in composer.json). Required for edge static caching rules, cloud.esi(...) dynamic islands inside cached pages, edge image transform constraints, and the csrfInput() requirement on cacheable pages.servd.yaml at the repo root or servd/craft-asset-storage in composer.json). Required for Servd static caching, {% dynamicInclude %} islands in cached pages, running Blitz in reverse-proxy mode, and off-server image transforms.Use WebFetch on specific doc pages when a reference file doesn't cover enough detail.
only on {% include %} — ambient variables leak in silently.{% if variant == 'x' %}) instead of extends/block.hero-button) instead of visual treatment (button--primary).utilities prop used as override — it's additive. Override via named-slot merge..eagerly() on relation fields in views — causes N+1 queries.devMode fallback in builders for unknown block types.bg-yellow-600) instead of brand tokens (bg-brand-accent).<a>, <button>, or <span> from props), links are navigation (always <a>). Separate atom categories.project-config/touch after editing YAML outside the CP — Git pulls, manual edits, and merge conflict resolution don't update dateModified. Run ddev craft project-config/touch then ddev craft up, or craft up on other environments won't detect the change.Read the relevant reference file(s) for your task. Multiple files often apply together.
Task examples:
atomic-patterns.md + composition-patterns.md + component-inventory.md + tailwind-conventions.mdboilerplate-routing.md + component-inventory.mdboilerplate-routing.md + composition-patterns.mdimage-presets.md + plugins/image-optimize.mdtailwind-conventions.mdjavascript-boundaries.mdtailwind-conventions.md + twig-collections.mdatomic-design.mdvite-buildchain.mdvite-buildchain.mdcraft.vite.* Twig function (asset, register, critical CSS)" → read plugins/vite.mdthird-party-integration.mdplugins/seomatic.mdplugins/blitz.mdplugins/formie.mdplugins/ckeditor.mdplugins/navigation.mdplugins/hyper.mdplugins/retour.mdplugins/timeloop.mdplugins/element-api.mdplugins/elements-panel.mdplugins/sherlock.mdplugins/embedded-assets.mdplugins/amazon-ses.md + third-party-integration.mdmulti-site-patterns.mdauth-flows.mdauth-account.mdauth-flows.mdmulti-site-patterns.mdmulti-site-patterns.mdplugins/sprig.mdplugins/sprig.mdplugins/feed-me.mdplugins/imager-x.mdsearch.mdsearch.md (Search Configuration)search.md (Rebuilding)feeds.mdfeeds.md (XML Sitemap)feeds.md (JSON Feed)headless.mdheadless.mdheadless.mdelement-partials.mdelement-partials.mdelement-partials.md| Reference | Scope |
|---|---|
references/atomic-design.md | Methodology: Brad Frost's atomic design principles, 5-to-3 tier compression, composability, context-agnostic naming, classification problem, decompose-downward workflow. Technology-independent. |
references/atomic-patterns.md | Individual component construction: props/extends/block pattern, variant file mechanics, button/link/text/icon atom implementations |
references/composition-patterns.md | Component composition: molecule pattern, organism pattern, structural embed pattern, include/extends/embed decision table, calling conventions, creating new components |
references/component-inventory.md | Classification methodology: decision tree, naming conventions, file naming, props design, scaffold guidelines, tier promotion, audit checklist |
references/boilerplate-routing.md | Template chain: layout hierarchy, Craft section template paths, global variables, routers, views, content builders, directory structure |
references/tailwind-conventions.md | Class composition: named-key collections, standard key names, utilities prop, variant-based dark mode, spacing preference. Assumes Tailwind CSS — adapt patterns to your CSS framework. |
references/vite-buildchain.md | Craft CMS Vite setup: nystudio107 plugin bridge, config/vite.php, vite.config.ts, craft.vite.script(), conditional per-page loading, Tailwind v4 integration, DDEV configuration |
references/image-presets.md | Image handling: single atom with presets, srcset/sizes, ImageOptimize vs Craft Cloud, hosting strategies |
references/javascript-boundaries.md | JS decision tree: Twig → Alpine/DataStar → Vue, mount points, data handoff, coexistence rules |
references/twig-collections.md | collect() method reference: creating, accessing, transforming, filtering, sorting, slicing, arrow functions |
references/third-party-integration.md | Script loading order, CMP (UserCentrics/CookieBot), GTM/sGTM data layer, analytics (Fathom/Plausible), AWS SES transport, n8n webhooks, Blitz compatibility, full head template example |
references/multi-site-patterns.md | Language switchers, hreflang tags, site architectures (subfolder/domain/subdomain/multi-brand), cross-site queries, static translations, site-specific templates, multi-site forms, site detection |
references/auth-flows.md | Front-end authentication forms: login, registration, password reset, set new password |
references/auth-account.md | Account management: edit profile, email verification, navigation partial, access control tags, user session helpers, GeneralConfig auth settings |
references/search.md | Search: syntax, Twig queries, configuration, indexing, rebuilding, score and ranking |
references/feeds.md | Feeds: RSS 2.0, Atom, JSON Feed, XML sitemap, custom routes, date filters |
references/headless.md | Headless & hybrid: headlessMode, GraphQL API, CORS, preview tokens, Next.js/Nuxt/Astro integration |
references/element-partials.md | Element partials: entry.render(), _partials/ directory, template lookup, custom variables, eager loading in partials |
Detailed configuration, Twig API, and pitfalls for Craft plugins. Located in references/plugins/.
| Reference | Plugin | Key Surface | |||
|---|---|---|---|---|---|
references/plugins/vite.md | Vite (nystudio107) | craft.vite.* Twig API (script, register, entry, asset, integrity, inline, includeCriticalCssTags, devServerRunning), vite.php config keys. Buildchain/vite.config.ts detail in references/vite-buildchain.md | |||
references/plugins/seomatic.md | SEOMatic (nystudio107) | Meta cascade, Twig get/set API, JSON-LD, custom element SEO bundles, sitemaps, GraphQL | |||
references/plugins/blitz.md | Blitz (putyourlightson) | Refresh modes, Twig dynamic content, driver architecture (storage/purger/deployer), Nginx rewrite, Cloudflare integration | |||
references/plugins/formie.md | Formie (verbb) | Form rendering (one-line/granular), theme config for Tailwind, submission querying, hooks, integrations | |||
references/plugins/image-optimize.md | ImageOptimize (nystudio107) | OptimizedImages field, imgTag()/pictureTag() builders, loading strategies, transform methods, console commands | |||
references/plugins/ckeditor.md | CKEditor (craftcms) | Field settings (toolbar, headings, image mode), nested entries with chunk rendering and value helpers, image mode (img vs entries), link configuration, GraphQL Mode, ES-module custom plugins, HTML Purifier, Redactor migration | |||
references/plugins/sprig.md | Sprig (putyourlightson) | Reactive Twig components (htmx), live search, load more, pagination, filtering, form submissions without JS | |||
references/plugins/colour-swatches.md | Colour Swatches (craftpulse) | Palette config, multi-colour swatches, Tailwind class mapping, Twig model API | |||
references/plugins/password-policy.md | Password Policy (craftpulse) | Validation rules, HIBP check, retention/expiry, console commands, recommended settings | |||
references/plugins/hyper.md | Hyper (verbb) | Link types, getLinkAttributes(), getText(), single/multi-link, element access, button atom integration | |||
references/plugins/retour.md | Retour (nystudio107) | Redirect types (exact/regex), 404 tracking, CSV import, auto slug-change redirects, config | |||
references/plugins/navigation.md | Navigation (verbb) | Node querying, custom rendering, active states, custom fields on nodes, GraphQL | |||
references/plugins/typogrify.md | Typogrify (nystudio107) | `\ | typogrify, \ | widont, \ | truncateOnWord`, smart quotes, widow prevention |
references/plugins/cache-igniter.md | Cache Igniter (putyourlightson) | GlobalPing warmer, geographic locations, refresh delay, Blitz companion | |||
references/plugins/knock-knock.md | Knock Knock (verbb) | Staging password protection, environment-aware config, URL exclusions | |||
references/plugins/timeloop.md | Timeloop (craftpulse) | Repeating date field, craft.timeloop variable API, recurringDates() function, GraphQL, period frequencies | |||
references/plugins/element-api.md | Element API (craftcms) | JSON API via config file, Fractal transformers, endpoint routing, pagination, caching | |||
references/plugins/elements-panel.md | Elements Panel (putyourlightson) | Debug toolbar panels for element population counts, duplicate detection, eager-loading opportunities | |||
references/plugins/sherlock.md | Sherlock (putyourlightson) | Security scanning, HTTP headers, CMS config checks, scheduled scans, IP restriction, monitoring | |||
references/plugins/embedded-assets.md | Embedded Assets (spicyweb) | oEmbed as first-class assets, craft.embeddedAssets.get(), iframe customization, GraphQL | |||
references/plugins/amazon-ses.md | Amazon SES (putyourlightson) | SES mail transport adapter, AWS credential config, SNS bounce tracking | |||
references/plugins/feed-me.md | Feed Me (craftcms) | Data import from XML/JSON/CSV, field mapping, duplicate handling, CLI automation | |||
references/plugins/imager-x.md | Imager-X (spacecatninja) | Advanced image transforms, batch generation, named presets, effects, optimizers, external storage |
One canonical component system across all projects. Atoms are context-agnostic — always named by visual treatment, never by parent. HTML element type is resolved from props (url → <a>, type → <button>, fallback → <span>).
External link detection is derived from the URL, never passed as a prop. Components auto-apply target="_blank", rel="noopener noreferrer", external icon, and sr-only text when a URL is external.
FontAwesome is the universal icon system. Icons are passed as FA class strings.
Visual variants use extends/block — base template defines structure, variant overrides classes. Never use conditional logic to switch between variant styles. For structural skeletons with content slots, use {% embed %} — see composition-patterns.md.
Image handling uses a single atom with config-driven presets, not separate variant files per context.
This skill assumes Tailwind CSS for class composition examples. Adapt patterns to your CSS framework — the architectural principles (named keys, additive utilities, semantic tokens) are framework-agnostic.
Class collections use named keys per style concern — this is the primary mechanism for preventing conflicts. The utilities prop is additive (extending), not overriding. Override specific concerns via named-slot merge.
Multi-brand theming uses CSS custom properties activated by data-brand="{{ currentSite.handle }}" on <html>. Components reference semantic Tailwind classes (bg-brand-accent) resolved via CSS variables. Template-level brand overrides only exist when the HTML structure itself differs between brands — not for color/font/spacing differences.
Token naming follows three layers: primitives (--brand-{color}-{shade}), semantics (--brand-{purpose}), and framework mapping (--color-brand-{purpose}).
Tailwind v4 cascade layers don't fix class conflicts within the same utilities layer. Named-key collections remain necessary.
PHP handles data, Twig handles presentation. Views receive data through includes — they never query it themselves.
collect() is used for both props and class building. The full Collection API is available in Twig via Craft.
The JS boundary follows a decision tree: Twig is the default → Alpine/DataStar for UI state → Vue for application state.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.