supabase
Handles the full Supabase workflow from schema changes to deployment, with built-in security guardrails that catch common traps like RLS...
Managing Cyril's Workshop blog posts and devblog via API - creating, editing, publishing, and updating content programmatically
Full skill instructions
This skill enables programmatic management of blog posts on steponnopets.net, including both the main Cyril blog and the devblog. Use this skill when the user asks to edit, update, or fix published blog posts.
When the user requests blog post edits or updates, follow these guidelines:
Identify the Target Post: Determine which post to edit from the user's request (by slug, "latest", or content description)
Read API Key: Always read the API key from ~/.claude/cyril-api-key before making API calls
Fetch Current Content: GET the post to see current state before making changes
Make Targeted Updates: Only PATCH the fields that need to change (title, content, tags, or publish status)
Confirm Success: Report the update with the post URL so the user can verify
Handle Both Blogs: DevBlog is at /devblog/api, main Cyril blog is at /cyril/api
User: Fix the typo in the admin panel post, change 'teh' to 'the'
Claude: I'll fetch the post, fix the typo, and update it:
- Read API key from ~/.claude/cyril-api-key
- Fetch post content from /devblog/api/posts
- Find the post about admin panel
- Replace 'teh' with 'the' in the content
- PATCH the updated content back
[Uses the PATCH Update pattern from reference material below]
Updated post "admin-panel-and-tag-filtering": https://steponnopets.net/devblog/#/post/admin-panel-and-tag-filtering
User: In the latest devblog post, change the repo link to https://github.com/lawless-m/Robocyril
Claude: I'll update the GitHub link in the most recent post:
- Fetch all posts from /devblog/api/posts
- Identify the latest by published_at timestamp
- Update the GitHub URL in the content
- PATCH just the content field
[Uses the PATCH Update pattern from reference material below]
User: Add 'automation' and 'admin' tags to the post about the admin panel
Claude: I'll update the tags for that post:
- Find the admin panel post by searching titles/slugs
- Get current tags array
- Add 'automation' and 'admin' to the array
- PATCH just the tags field
[Uses the PATCH Update pattern from reference material below]
User: Change the title of the post 'old-slug' to 'Better New Title'
Claude: I'll update the title while keeping the same slug:
- Fetch post by slug 'old-slug'
- PATCH with new title only
- Note: Slug stays the same (it's the identifier)
[Uses the PATCH Update pattern from reference material below]
The sections below contain working patterns and exact API formats for managing blog posts.
https://steponnopets.net/devblogGET /devblog/api/postsGET /devblog/api/posts?include_drafts=true (requires auth)GET /devblog/api/post?slug=<slug>POST /devblog/api/postsPATCH /devblog/api/post?slug=<slug>DELETE /devblog/api/post?slug=<slug>https://steponnopets.net/cyril/devblog/ with /cyril/Location: ~/.claude/cyril-api-key
Purpose: Authenticate all write operations
All POST, PATCH, and DELETE requests require:
-H "X-Cyril-Key: $(cat ~/.claude/cyril-api-key)"
Key Points:
?include_drafts=true requires authPurpose: Fetch current post content before editing
Get all published posts:
curl https://steponnopets.net/devblog/api/posts
Get single post by slug:
curl "https://steponnopets.net/devblog/api/post?slug=my-post-slug"
Response format:
{
"slug": "post-title",
"title": "Post Title",
"content": "# Markdown content...",
"tags": ["rust", "web"],
"repo": "https://github.com/user/repo",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:30:00Z",
"published_at": "2025-01-15T10:30:00Z"
}
Key Points:
published_at = nullPurpose: Update specific fields of an existing post
ALWAYS use this exact pattern:
curl -X PATCH "https://steponnopets.net/devblog/api/post?slug=<slug>" \
-H "Content-Type: application/json" \
-H "X-Cyril-Key: $(cat ~/.claude/cyril-api-key)" \
-d '{
"content": "# Updated content..."
}'
All fields are optional - only include what you want to update:
| Field | Type | Description |
|---|---|---|
title | string | Update post title (slug stays same) |
content | string | Update full markdown content |
tags | array | Replace all tags (["tag1", "tag2"]) |
publish | boolean | true to publish, false to unpublish |
Example updating multiple fields:
curl -X PATCH "https://steponnopets.net/devblog/api/post?slug=my-post" \
-H "Content-Type: application/json" \
-H "X-Cyril-Key: $(cat ~/.claude/cyril-api-key)" \
-d '{
"title": "New Title",
"tags": ["rust", "svelte", "automation"],
"publish": true
}'
Key Points:
Purpose: Create a new blog post (usually done via /blog command)
IMPORTANT: Always use the file-based approach to avoid JSON escaping issues, especially on Windows.
Format (recommended - works on all platforms):
# 1. Write post data to temporary file
cat > /tmp/post.json << 'EOF'
{
"title": "Post Title",
"content": "# Markdown content here...",
"repo": "https://github.com/user/repo",
"tags": ["® RepoName", "rust", "web"],
"publish": true
}
EOF
# 2. POST the file
curl -X POST https://steponnopets.net/cyril/api/posts \
-H "Content-Type: application/json" \
-H "X-Cyril-Key: $(cat ~/.claude/cyril-api-key)" \
--data-binary @/tmp/post.json
# 3. Clean up
rm /tmp/post.json
Windows alternative:
# Use Write tool to create post.json in current directory
# Then:
curl -X POST https://steponnopets.net/cyril/api/posts `
-H "Content-Type: application/json" `
-H "X-Cyril-Key: <api-key>" `
--data-binary @post.json
Response:
{
"slug": "post-title",
"url": "https://steponnopets.net/cyril/#/post/post-title"
}
Key Points:
® RepoName"publish": false to save as draft--data-binary @file.json to avoid shell escaping issuesPurpose: Delete a blog post
curl -X DELETE "https://steponnopets.net/devblog/api/post?slug=my-post-slug" \
-H "X-Cyril-Key: $(cat ~/.claude/cyril-api-key)"
Key Points:
Posts are stored in SQLite at /var/www/data/devblog.db and /var/www/data/cyril.db:
CREATE TABLE posts (
slug TEXT PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
tags TEXT, -- JSON array: ["tag1", "tag2"]
repo TEXT,
created_at TEXT,
updated_at TEXT,
published_at TEXT -- NULL for drafts
)
Purpose: Auto-create project entries from blog posts
When a post has a project tag (® ProjectName) as the first tag:
repo fieldExample:
{
"title": "Building Robocyril Admin Panel",
"tags": ["® Robocyril", "rust", "svelte"],
"repo": "https://github.com/lawless-m/Robocyril",
"content": "This post describes building an admin panel.\n\nMore details..."
}
Creates/updates project:
When the user makes these requests, use these patterns:
| User Request | Action | Fields to PATCH |
|---|---|---|
| "Fix typo X to Y" | Search & replace in content | content |
| "Add tag Z" | Append to tags array | tags |
| "Change title to X" | Replace title | title |
| "Update GitHub link" | Replace URL in content | content |
| "Unpublish post X" | Set publish to false | publish |
| "Publish draft X" | Set publish to true | publish |
| Status | Meaning | Action |
|---|---|---|
| 404 | Post not found | Verify slug, check if post exists |
| 401 | Invalid API key | Check ~/.claude/cyril-api-key contents |
| 400 | Invalid JSON | Verify JSON syntax in request |
| 500 | Server error | Check vsprod logs |
Web-based admin available at https://steponnopets.net/devblog/#/admin:
published_at to distinguish drafts from published postsHandles the full Supabase workflow from schema changes to deployment, with built-in security guardrails that catch common traps like RLS...
Comprehensive guides and best practices for Neon Serverless Postgres, covering setup, connection methods, authentication, and platform APIs.
Guide for setting up and using Firebase Authentication. Use this skill when the user's app requires user sign-in, user management, or secure data access using auth rules.
A skill to evaluate how secure Firestore security rules are. Use this when Firestore security rules are updated to ensure that the generated rules are extremely secure and robust.
Official skill for integrating Firebase AI Logic (Gemini API) into web applications. Covers setup, multimodal inference, structured output, and security.
Complete Better Auth server and client setup with database adapters, session management, plugins, and security configuration.
Deploy and manage projects on Vercel using token-based authentication. Use when working with Vercel CLI using access tokens rather than interactive login — e.g. "deploy to vercel", "set up vercel", "add environment variables to vercel".
Complete Cloudflare platform integration with decision trees for compute, storage, AI, networking, security, and infrastructure-as-code.
Run Azure compliance and security audits with azqr plus Key Vault expiration checks. Covers best-practice assessment, resource review, policy/compliance validation, and security posture checks. WHEN: compliance scan, security audit, BEFORE running azqr (compliance cli tool), Azure best practices, Key Vault expiration check, expired certificates, expiring secrets, orphaned resources, compliance assessment.
Send, read, and manage Gmail messages, drafts, labels, and account settings.
Comprehensive website auditing across 230+ rules in 21 categories including SEO, performance, security, and accessibility.
Shared authentication, CLI syntax, and output formatting patterns for gws Google Workspace commands.
Discover your celebrity doppelgänger with StarByFace!
GeoSpy: Pricing, Features, FAQs, and Alternatives for AI Teams
Detect AI-generated voices to protect against audio fraud.
Ensure Your Content's Originality with AI Plagiarism Checker
Upscale images by 400% without quality loss
Protect your social media from copyright disputes
Accurately Detect AI-Generated Content with TheChecker.AI
Chrome extension that detects and flags AI-generated content