Refactor high-complexity React components in Dify frontend. Use when `pnpm analyze-component...
npx skills add jezweb/claude-skills --skill "sveltia-cms"
Install specific skill from multi-skill repository
# Description
|
# SKILL.md
name: sveltia-cms
description: |
Set up Sveltia CMS - lightweight Git-backed CMS successor to Decap/Netlify CMS (300KB bundle, 270+ fixes). Framework-agnostic for Hugo, Jekyll, 11ty, Astro. Prevents 10 documented errors.
Use when adding CMS to static sites, migrating from Decap CMS, or fixing OAuth, YAML parse, datetime timezone, GDPR font loading, or CORS/COOP errors.
user-invocable: true
allowed-tools: ['Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep']
Sveltia CMS Skill
Complete skill for integrating Sveltia CMS into static site projects.
Current Versions
- @sveltia/cms: 0.128.5 (verified January 2026)
- Status: Public Beta (v1.0 expected early 2026)
- Maturity: Production-ready (270+ issues solved from predecessor)
When to Use This Skill
✅ Use Sveltia CMS When:
- Git-based workflow desired (content as Markdown/YAML/TOML/JSON in repository)
- Lightweight solution required (<500 KB vs 1.5-2.6 MB for competitors)
- Migrating from Decap/Netlify CMS (drop-in replacement, change 1 line)
- Non-technical editors need access without Git knowledge
❌ Don't Use Sveltia CMS When:
- Real-time collaboration needed (multiple users editing simultaneously) - Use Sanity, Contentful, or TinaCMS instead
- Visual page building required (drag-and-drop) - Use Webflow, Builder.io instead
- React-specific visual editing needed - Use TinaCMS instead
Breaking Changes & Updates (v0.105.0+)
v0.127.0 (December 29, 2025) - slug_length Deprecation
DEPRECATION: The slug_length collection option is deprecated and will be removed in v1.0.
Migration:
# ❌ Deprecated (pre-v0.127.0)
collections:
- name: posts
slug_length: 50
# ✅ New (v0.127.0+)
slug:
maxlength: 50
Timeline: Will be removed in Sveltia CMS 1.0 (expected early 2026).
Source: Release v0.127.0
v0.120.0 (November 24, 2025) - Author Template Tags
New Feature: Hidden widget now supports author template tags:
- {{author-email}} - Signed-in user's email
- {{author-login}} - Signed-in user's login name
- {{author-name}} - Signed-in user's display name
Usage:
fields:
- label: Author Email
name: author_email
widget: hidden
default: '{{author-email}}'
Commit message templates also support {{author-email}} tag.
v0.119.0 (November 16, 2025) - TOML Config Support
New Feature: Configuration files can now be written in TOML format (previously YAML-only).
Migration:
# admin/config.toml (NEW)
[backend]
name = "github"
repo = "owner/repo"
branch = "main"
media_folder = "static/images/uploads"
public_folder = "/images/uploads"
Recommendation: YAML is still preferred for better tooling support.
v0.118.0 (November 15, 2025) - TypeScript Breaking Change
BREAKING: Renamed SiteConfig export to CmsConfig for compatibility with Netlify/Decap CMS.
Migration:
// ❌ Old (v0.117.x)
import type { SiteConfig } from '@sveltia/cms';
// ✅ New (v0.118.0+)
import type { CmsConfig } from '@sveltia/cms';
const config: CmsConfig = {
backend: { name: 'github', repo: 'owner/repo' },
collections: [/* ... */],
};
Impact: TypeScript users only. Breaking change for type imports.
v0.117.0 (November 14, 2025) - Enhanced Validation
New Features:
- Exported CmsConfig type for direct TypeScript import
- Enhanced config validation for collection names, field types, and relation references
- Better error messages for invalid configurations
v0.115.0 (November 5, 2025) - Field-Specific Media Folders
New Feature: Override media_folder at the field level (not just collection level).
Usage:
collections:
- name: posts
label: Blog Posts
folder: content/posts
media_folder: static/images/posts # Collection-level default
fields:
- label: Featured Image
name: image
widget: image
media_folder: static/images/featured # ← Field-level override
public_folder: /images/featured
- label: Author Avatar
name: avatar
widget: image
media_folder: static/images/avatars # ← Another override
public_folder: /images/avatars
Use case: Different media folders for different image types in same collection.
v0.113.5 (October 27, 2025) - Logo Deprecation
DEPRECATION: logo_url option is now deprecated. Migrate to logo.src.
Migration:
# ❌ Deprecated
logo_url: https://yourdomain.com/logo.svg
# ✅ New (v0.113.5+)
logo:
src: https://yourdomain.com/logo.svg
v0.105.0 (September 15, 2024) - Security Breaking Change
BREAKING: sanitize_preview default changed to true for Markdown widget (XSS prevention).
Impact:
- Before v0.105.0: sanitize_preview: false (compatibility with Netlify/Decap CMS, but vulnerable to XSS)
- After v0.105.0: sanitize_preview: true (secure by default)
Migration:
collections:
- name: posts
fields:
- label: Body
name: body
widget: markdown
sanitize_preview: false # ← Add ONLY if you trust all CMS users
Recommendation: Keep default (true) unless disabling fixes broken preview AND you fully trust all CMS users.
Configuration Options
Global Slug Options (v0.128.0+)
Configure slug generation behavior globally:
slug:
encoding: unicode-normalized
clean_accents: false
sanitize_replacement: '-'
lowercase: true # Default: convert to lowercase (v0.128.0+)
maxlength: 50 # Default: unlimited (v0.127.0+)
lowercase (v0.128.0+): Set to false to preserve original casing in slugs (e.g., "MyBlogPost" instead of "myblogpost").
Use case: Mixed-case URLs or file names where case matters.
Source: Release v0.128.0, GitHub Issue #594
Raw Format for Text Files (v0.126.0+)
New raw format allows editing files without front matter (CSV, JSON, YAML, plain text). Must have single body field with widget type: code, markdown, richtext, or text.
Use Cases:
- Edit configuration files (JSON, YAML)
- Manage CSV data
- Edit plain text files
Configuration:
collections:
- name: config
label: Configuration Files
files:
- label: Site Config
name: site_config
file: config.json
format: raw # ← NEW format type
fields:
- label: Config
name: body
widget: code
default_language: json
Restrictions:
- Only one field allowed (must be named body)
- Widget must be: code, markdown, richtext, or text
- No front matter parsing
Source: Release v0.126.0
Number Field String Encoding (v0.125.0+)
New value_type option for Number field accepts int/string and float/string to save numbers as strings instead of numbers in front matter.
Use Case: Some static site generators or schemas require numeric values stored as strings (e.g., age: "25" instead of age: 25).
Configuration:
fields:
- label: Age
name: age
widget: number
value_type: int/string # Saves as "25" not 25
- label: Price
name: price
widget: number
value_type: float/string # Saves as "19.99" not 19.99
Source: Release v0.125.0, GitHub Issue #574
Editor Pane Locale via URL Query (v0.126.0+)
Override editor locale via URL query parameter ?_locale=fr to get edit links for specific locales.
Use Case: Generate direct edit links for translators or content editors for specific languages.
Example:
https://yourdomain.com/admin/#/collections/posts/entries/my-post?_locale=fr
Source: Release v0.126.0, GitHub Issue #585
Richtext Field Type Alias (v0.124.0+)
Added richtext as an alias for markdown widget to align with Decap CMS terminology. Both work identically.
Configuration:
fields:
- label: Body
name: body
widget: richtext # ← NEW alias for markdown
Future: HTML output support planned for richtext field type.
Source: Release v0.124.0
Setup Pattern (Framework-Agnostic)
All frameworks follow the same pattern:
- Create admin directory in public/static folder:
- Hugo:
static/admin/ - Jekyll:
admin/ - 11ty:
admin/(with passthrough copy) - Astro:
public/admin/ -
Next.js:
public/admin/ -
Create admin/index.html:
```html
```
- Create admin/config.yml:
```yaml
backend:
name: github
repo: owner/repo
branch: main
base_url: https://your-worker.workers.dev # OAuth proxy (required)
media_folder: static/images/uploads # Framework-specific path
public_folder: /images/uploads
collections:
- name: posts
label: Blog Posts
folder: content/posts
create: true
fields:
- { label: 'Title', name: 'title', widget: 'string' }
- { label: 'Date', name: 'date', widget: 'datetime' }
- { label: 'Body', name: 'body', widget: 'markdown' }
```
- Access admin:
http://localhost:<port>/admin/
Framework-specific details: See templates/ directory for complete examples.
Authentication: Cloudflare Workers OAuth (Recommended)
Why Cloudflare Workers: Fastest, free tier available, works with any deployment platform.
Steps:
-
Deploy Worker:
bash git clone https://github.com/sveltia/sveltia-cms-auth cd sveltia-cms-auth npm install npx wrangler deploy -
Register OAuth App on GitHub:
- Go to https://github.com/settings/developers
- Click "New OAuth App"
- Authorization callback URL:
https://your-worker.workers.dev/callback -
Save Client ID and Client Secret
-
Configure Worker Environment Variables:
```bash
npx wrangler secret put GITHUB_CLIENT_ID
# Paste your Client ID
npx wrangler secret put GITHUB_CLIENT_SECRET
# Paste your Client Secret
```
-
Update CMS config:
yaml backend: name: github repo: owner/repo branch: main base_url: https://your-worker.workers.dev # ← Add this line -
Test authentication:
- Open
/admin/ - Click "Login with GitHub"
- Should redirect to GitHub → Authorize → Back to CMS
Alternative: Vercel serverless functions - See templates/vercel-serverless/
Common Errors & Solutions
This skill prevents 10 common errors encountered when setting up Sveltia CMS.
1. ❌ OAuth Authentication Failures
Error Message:
- "Error: Failed to authenticate"
- Redirect to https://api.netlify.com/auth instead of GitHub login
Symptoms:
- Login button does nothing
- Authentication popup closes immediately
Causes:
- Missing base_url in backend config
- Incorrect OAuth proxy URL
- Wrong GitHub OAuth callback URL
Solution:
Step 1: Verify config.yml has base_url:
backend:
name: github
repo: owner/repo
branch: main
base_url: https://your-worker.workers.dev # ← Must be present
Step 2: Check GitHub OAuth App callback:
- Should be: https://your-worker.workers.dev/callback
- NOT: https://yourdomain.com/callback
Step 3: Test Worker directly:
curl https://your-worker.workers.dev/health
# Should return: {"status": "ok"}
2. ❌ TOML Front Matter Errors
Error Message:
- "Parse error: Invalid TOML"
- Files missing +++ delimiters
Symptoms:
- New files created by CMS don't parse in Hugo
- Content appears above body separator
Causes:
- Sveltia's TOML generation is buggy in beta
- Mixed TOML/YAML in same collection
Solution:
Use YAML instead of TOML (recommended):
collections:
- name: posts
folder: content/posts
format: yaml # or md (Markdown with YAML frontmatter)
# NOT: format: toml
If you must use TOML:
1. Manually fix delimiters after CMS saves
2. Use pre-commit hook to validate TOML
3. Wait for beta fixes (track GitHub issues)
3. ❌ YAML Parse Errors
Error Message:
- "YAML parse error: Invalid YAML"
- "Error: Duplicate key 'field_name'"
Symptoms:
- Existing posts won't load in CMS
- CMS shows empty fields
Causes:
- Sveltia is stricter than Hugo/Jekyll about YAML formatting
- Incorrect indentation or smart quotes
Solution:
Step 1: Validate YAML:
pip install yamllint
find content -name "*.md" -exec yamllint {} \;
Step 2: Common fixes:
Problem: Smart quotes
# ❌ Bad - smart quotes from copy-paste
title: "Hello World" # Curly quotes
# ✅ Good - straight quotes
title: "Hello World" # Straight quotes
Step 3: Auto-fix with yamlfmt:
go install github.com/google/yamlfmt/cmd/yamlfmt@latest
find content -name "*.md" -exec yamlfmt {} \;
4. ❌ Content Not Listing in CMS
Error Message:
- "No entries found"
- "Failed to load entries"
Symptoms:
- Admin loads but shows no content
- Files exist in repository but CMS doesn't see them
Causes:
- Format mismatch (config expects TOML, files are YAML)
- Incorrect folder path
Solution:
Step 1: Verify folder path:
# Config says:
collections:
- name: posts
folder: content/posts # Expects files here
# Check actual location:
ls -la content/posts # Files must exist here
Step 2: Match format to actual files:
# If files are: content/posts/hello.md with YAML frontmatter
collections:
- name: posts
folder: content/posts
format: yaml # or md (same as yaml for .md files)
5. ❌ "SVELTIA is not defined" Error
Error Message:
- Console error: Uncaught ReferenceError: SVELTIA is not defined
Symptoms:
- Admin page shows white screen
Causes:
- Missing type="module" attribute
Solution:
Use correct script tag:
<!-- ✅ Correct -->
<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js" type="module"></script>
<!-- ❌ Wrong - missing type="module" -->
<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>
Use version pinning (recommended):
<script src="https://unpkg.com/@sveltia/[email protected]/dist/sveltia-cms.js" type="module"></script>
6. ❌ 404 on /admin
Error Message:
- "404 Not Found" when visiting /admin/
Symptoms:
- Works locally but not in production
Causes:
- Admin directory not in correct location for framework
Solution:
Framework-specific fixes:
Hugo: Files in static/ are automatically copied
Jekyll: Add to _config.yml:
include:
- admin
11ty: Add to .eleventy.js:
module.exports = function(eleventyConfig) {
eleventyConfig.addPassthroughCopy('admin');
};
Astro: Files in public/ are automatically copied
7. ❌ Images Not Uploading (HEIC Format)
Error Message:
- "Unsupported file format"
Symptoms:
- iPhone photos won't upload
Causes:
- HEIC format not supported by browsers
Solution:
On iPhone:
- Settings > Camera > Formats > Most Compatible
- This saves photos as JPEG instead of HEIC
Or enable image optimization:
media_libraries:
default:
config:
max_file_size: 10485760 # 10 MB
transformations:
raster_image:
format: webp # Auto-converts to WebP
quality: 85
8. ❌ Datetime Widget Format Strictness
Error Message:
- Silent data loss (no error shown)
- Date fields show blank in CMS
Symptoms:
- Posts with existing dates appear blank when editing
- Saving overwrites dates with blank values
- Hugo marks posts as "future" and skips building them
Causes:
- Default datetime widget outputs timestamps WITHOUT timezone suffix
- When format is specified, Sveltia becomes strict - existing entries with different formats show as blank
- Hugo infers UTC when timezone missing, causing timezone issues
⚠️ CRITICAL: Format Strictness Warning (v0.124.1+)
When you specify a format option, Sveltia becomes strict:
- Existing entries with different formats show as blank
- Saving will overwrite with blank value (SILENT DATA LOSS)
- No error message shown
Solution:
Option 1: Use picker_utc (Recommended)
fields:
- label: Date
name: date
widget: datetime
picker_utc: true # Most flexible - outputs with timezone
Option 2: Specify format with timezone (RISKY - see warning above)
fields:
- label: Date
name: date
widget: datetime
format: "YYYY-MM-DDTHH:mm:ss.SSSZ" # Only if ALL existing dates match this format
Option 3: Configure Hugo to accept missing timezone
# config.toml
[frontmatter]
date = [":default", ":fileModTime"]
Prevention:
1. Don't specify format if you have mixed date formats
2. Normalize all dates first before adding format
3. Use picker_utc: true instead (more flexible)
Source: GitHub Issue #565, fixed in v0.126.0 (improved date parser but format strictness remains)
9. ❌ GDPR Violation: Google Fonts CDN
Error Message:
- No error shown (privacy compliance issue)
Symptoms:
- Privacy-focused sites blocked from using Sveltia
- EU public sector cannot adopt
- GDPR non-compliance
Causes:
- Sveltia loads Google Fonts and Material Symbols from Google CDN without user consent
- Google tracks font usage and collects IP addresses
- Violates EU data protection law
⚠️ Impact: Blocking issue for EU public sector and privacy-focused sites
Solution (Vite Plugin - Recommended):
// vite.config.ts
import { defineConfig, type Plugin } from 'vite'
function ensureGDPRCompliantFonts(): Plugin {
const fontsURLRegex = /fonts\.googleapis\.com\/css2/g
const replacement = 'fonts.bunny.net/css'
return {
name: 'gdpr-compliant-fonts',
enforce: 'post',
transform(code) {
if (fontsURLRegex.test(code)) {
return code.replaceAll(fontsURLRegex, replacement)
}
},
}
}
export default defineConfig({
plugins: [ensureGDPRCompliantFonts()],
})
Alternative Solutions:
Option 2: Bunny Fonts (1:1 Google Fonts replacement)
- Use https://fonts.bunny.net instead of fonts.googleapis.com
- EU-based, GDPR-compliant
- Same API as Google Fonts
Option 3: Self-hosted fonts
- Use @fontsource npm packages
- Bundle fonts with application
- No external requests
Maintainer Response:
- Acknowledged issue
- Plans to add system font option (post-v1.0)
- Sveltia itself collects no data (fonts are only concern)
Source: GitHub Issue #443
10. ❌ CORS / COOP Policy Errors
Error Message:
- "Authentication Aborted"
- "Cross-Origin-Opener-Policy blocked"
Symptoms:
- OAuth popup opens then closes
Causes:
- Strict Cross-Origin-Opener-Policy header blocking OAuth
Solution:
Cloudflare Pages (_headers file):
/*
Cross-Origin-Opener-Policy: same-origin-allow-popups
# NOT: same-origin (this breaks OAuth)
Netlify (_headers file):
/*
Cross-Origin-Opener-Policy: same-origin-allow-popups
Vercel (vercel.json):
{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Cross-Origin-Opener-Policy",
"value": "same-origin-allow-popups"
}
]
}
]
}
Fixed Issues (Historical Reference)
These issues were present in earlier versions but have been fixed. Documented here for reference.
✅ Paths with Parentheses Break Entry Loading (Fixed in v0.128.1)
Issue: Sveltia CMS failed to load existing entries when the path option contains parentheses (). This affected Next.js/Nextra users using route groups like app/(content)/(writing)/.
Symptoms (pre-v0.128.1):
- Creating new entries worked
- Loading/listing existing entries failed silently
- CMS showed "No entries found" despite files existing
Example that failed:
collections:
- name: pages
folder: app/(pages)
path: "{{slug}}/page" # ← Failed to load existing entries
extension: mdx
Status: Fixed in v0.128.1 (January 13, 2026)
Source: GitHub Issue #596
✅ Root Folder Collections Break GitHub Backend (Fixed in v0.125.0)
Issue: Collections with folder: "" or folder: "." or folder: "/" failed when creating new entries via GitHub backend. GraphQL query incorrectly constructed path starting with / (absolute) instead of relative path.
Symptoms (pre-v0.125.0):
- Worked locally via browser File API
- Failed with GitHub backend (GraphQL error)
- Leading slash broke GraphQL mutation
Example that failed:
collections:
- name: root-pages
folder: "" # or "." or "/"
# ← Broke when creating entries via GitHub backend
Use Case: VitePress and other frameworks storing content at repository root.
Status: Fixed in v0.125.0 (December 20, 2025)
Source: GitHub Issue #580
Migration from Decap CMS
Sveltia CMS is a drop-in replacement for Decap CMS.
Step 1: Update script tag (1 line change):
<!-- OLD: Decap CMS -->
<script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>
<!-- NEW: Sveltia CMS -->
<script src="https://unpkg.com/@sveltia/[email protected]/dist/sveltia-cms.js" type="module"></script>
Step 2: Keep existing config.yml (no changes needed)
Step 3: Test locally (verify login, content listing, editing, saving)
That's it! Your content, collections, and workflows remain unchanged.
Not Supported:
- Git Gateway backend (for performance reasons)
- Azure backend (may be added later)
Workaround: Use Cloudflare Workers or Vercel OAuth proxy instead.
Bundled Resources
Templates
- hugo/ - Complete Hugo blog setup
- jekyll/ - Jekyll site configuration
- 11ty/ - Eleventy blog setup
- astro/ - Astro content collections
- cloudflare-workers/ - OAuth proxy implementation
- vercel-serverless/ - Vercel auth functions
- collections/ - Pre-built collection patterns
References
- common-errors.md - Extended error troubleshooting
- migration-from-decap.md - Complete migration guide
- cloudflare-auth-setup.md - Step-by-step OAuth setup
- config-reference.md - Full config.yml documentation
Scripts
- init-sveltia.sh - Automated setup for new projects
- deploy-cf-auth.sh - Deploy Cloudflare Workers OAuth
Official Documentation
- Documentation Site: https://sveltiacms.app/en/docs (under active development - some sections may be incomplete)
- GitHub: https://github.com/sveltia/sveltia-cms
- OAuth Worker: https://github.com/sveltia/sveltia-cms-auth
- npm Package: https://www.npmjs.com/package/@sveltia/cms
- Discussions: https://github.com/sveltia/sveltia-cms/discussions
Note: The official documentation site is being actively developed. GitHub README remains a useful fallback for some topics.
Token Efficiency
Estimated Savings: 65-70% (~6,300 tokens saved)
Without Skill (~9,500 tokens):
- Framework setup trial & error: 2,500 tokens
- OAuth configuration attempts: 2,500 tokens
- Error troubleshooting: 2,500 tokens
- Deployment configuration: 2,000 tokens
With Skill (~3,200 tokens):
- Skill loading (SKILL.md): 2,000 tokens
- Template selection: 400 tokens
- Project-specific adjustments: 800 tokens
Errors Prevented
This skill prevents 10 common errors (100% prevention rate):
- ✅ OAuth authentication failures
- ✅ TOML front matter generation bugs
- ✅ YAML parse errors (strict validation)
- ✅ Content not listing in CMS
- ✅ "SVELTIA is not defined" errors
- ✅ 404 on /admin page
- ✅ Image upload failures (HEIC format)
- ✅ Datetime widget format strictness / timezone issues
- ✅ GDPR violation (Google Fonts CDN)
- ✅ CORS / COOP policy errors
Last Updated: 2026-01-21
Skill Version: 2.1.0
Sveltia CMS Version: 0.128.5 (Beta)
Status: Production-ready, v1.0 GA expected early 2026
Changes: Added 6 new configuration options (slug lowercase, raw format, number string encoding, locale URL param, richtext alias, Gemini 2.5 Flash-Lite support), updated datetime error with format strictness warning, added GDPR Google Fonts workaround, documented 2 fixed historical issues, deprecated slug_length option
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.