Set up Sveltia CMS - lightweight Git-backed CMS successor to Decap/Netlify CMS (300KB bundle, 270+ fixes). Framework-agnostic for Hugo, Jekyll, 11ty, Astro. Use when adding CMS to static sites, migrating from Decap CMS, or fixing OAuth, YAML parse, CORS/COOP errors.
/plugin marketplace add jezweb/claude-skills/plugin install jezweb-tooling-skills@jezweb/claude-skillsThis skill is limited to using the following tools:
README.mdreferences/migration-from-decap.mdscripts/check-versions.shscripts/init-sveltia.shtemplates/11ty/config.ymltemplates/11ty/index.htmltemplates/cloudflare-workers/setup-guide.mdtemplates/cloudflare-workers/wrangler.jsonctemplates/collections/blog-posts.ymltemplates/collections/docs-pages.ymltemplates/collections/landing-pages.ymltemplates/hugo/config.ymltemplates/hugo/index.htmltemplates/jekyll/config.ymltemplates/jekyll/index.htmlComplete skill for integrating Sveltia CMS into static site projects.
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 nameUsage:
fields:
- label: Author Email
name: author_email
widget: hidden
default: '{{author-email}}'
Commit message templates also support {{author-email}} tag.
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.
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.
New Features:
CmsConfig type for direct TypeScript importNew 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.
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
BREAKING: sanitize_preview default changed to true for Markdown widget (XSS prevention).
Impact:
sanitize_preview: false (compatibility with Netlify/Decap CMS, but vulnerable to XSS)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.
All frameworks follow the same pattern:
Create admin directory in public/static folder:
static/admin/admin/admin/ (with passthrough copy)public/admin/public/admin/Create admin/index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Content Manager</title>
</head>
<body>
<script src="https://unpkg.com/@sveltia/cms@0.127.0/dist/sveltia-cms.js" type="module"></script>
</body>
</html>
Create admin/config.yml:
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.
Why Cloudflare Workers: Fastest, free tier available, works with any deployment platform.
Steps:
Deploy Worker:
git clone https://github.com/sveltia/sveltia-cms-auth
cd sveltia-cms-auth
npm install
npx wrangler deploy
Register OAuth App on GitHub:
https://your-worker.workers.dev/callbackConfigure Worker Environment Variables:
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:
backend:
name: github
repo: owner/repo
branch: main
base_url: https://your-worker.workers.dev # ← Add this line
Test authentication:
/admin/Alternative: Vercel serverless functions - See templates/vercel-serverless/
This skill prevents 8 common errors encountered when setting up Sveltia CMS.
Error Message:
https://api.netlify.com/auth instead of GitHub loginSymptoms:
Causes:
base_url in backend configSolution:
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:
https://your-worker.workers.dev/callbackhttps://yourdomain.com/callbackStep 3: Test Worker directly:
curl https://your-worker.workers.dev/health
# Should return: {"status": "ok"}
Error Message:
+++ delimitersSymptoms:
Causes:
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:
Error Message:
Symptoms:
Causes:
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 {} \;
Error Message:
Symptoms:
Causes:
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)
Error Message:
Uncaught ReferenceError: SVELTIA is not definedSymptoms:
Causes:
type="module" attributeSolution:
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/cms@0.127.0/dist/sveltia-cms.js" type="module"></script>
Error Message:
/admin/Symptoms:
Causes:
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
Error Message:
Symptoms:
Causes:
Solution:
On iPhone:
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
Error Message:
Symptoms:
Causes:
Cross-Origin-Opener-Policy header blocking OAuthSolution:
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"
}
]
}
]
}
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/cms@0.127.0/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:
Workaround: Use Cloudflare Workers or Vercel OAuth proxy instead.
Estimated Savings: 65-70% (~6,300 tokens saved)
Without Skill (~9,500 tokens):
With Skill (~3,200 tokens):
This skill prevents 8 common errors (100% prevention rate):
Last Updated: 2026-01-09 Skill Version: 2.0.1 Sveltia CMS Version: 0.127.0 (Beta) Status: Production-ready, v1.0 GA expected early 2026
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.