skills/ghost-blog/SKILL.md
Quản lý bài Ghost qua Admin API: list/filter, CRUD, bulk, tag.
npx skillsauth add hoangvantuan/claude-plugin ghost-blogInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Manage Ghost CMS posts and tags via Admin API.
cd .claude/skills/ghost-blog/scripts
uv venv
uv pip install -r requirements.txt
cd .claude/skills/ghost-blog/scripts
cp .env.example .env
# Edit .env with your Ghost credentials
.env file:
GHOST_URL=https://your-blog.ghost.io
GHOST_ADMIN_KEY=your-key-id:your-secret-key
GHOST_API_VERSION=v5.0
Get your Admin API Key:
id:secret)cd .claude/skills/ghost-blog/scripts && uv run python ghost_core.py
List posts:
python scripts/posts_browse.py --status draft
python scripts/posts_browse.py --tag news --featured
Manage single post:
python scripts/posts_crud.py get --id POST_ID
python scripts/posts_crud.py create --title "New Post" --html "<p>Content</p>"
python scripts/posts_crud.py publish --id POST_ID
Bulk operations:
python scripts/posts_bulk.py publish --filter "status:draft" --execute
python scripts/posts_bulk.py add-tag --filter "status:published" --tag "archive" --execute
Manage tags:
python scripts/tags_manage.py list
python scripts/tags_manage.py create --name "Tutorial"
| User Intent | Script | Example Command |
| ------------------------------------- | ------------------------- | ------------------------------------ |
| test, run tests | pytest | cd scripts && uv run pytest -v |
| list posts, show drafts, filter posts | posts_browse.py | --status draft --tag news |
| get post, read post, show post | posts_crud.py get | --id xxx or --slug xxx |
| create post, new post, write post | posts_crud.py create | --title "..." --html "..." |
| update post, edit post, change post | posts_crud.py update | --id xxx --title "..." |
| delete post, remove post | posts_crud.py delete | --id xxx --confirm |
| publish post, publish draft | posts_crud.py publish | --id xxx |
| unpublish post | posts_crud.py unpublish | --id xxx |
| bulk publish, publish all drafts | posts_bulk.py publish | --filter "..." --execute |
| bulk unpublish | posts_bulk.py unpublish | --filter "..." --execute |
| add tag to posts, tag posts | posts_bulk.py add-tag | --filter "..." --tag xxx --execute |
| remove tag from posts | posts_bulk.py remove-tag | --filter "..." --tag xxx --execute |
| list tags, show tags | tags_manage.py list | (no options needed) |
| create tag, new tag | tags_manage.py create | --name "..." |
| delete tag, remove tag | tags_manage.py delete | --slug xxx --confirm |
| Script | Purpose |
| ----------------- | --------------------------------------------- |
| ghost_core.py | Shared: JWT auth, HTTP client, error handling |
| posts_browse.py | List, filter, search posts |
| posts_crud.py | CRUD operations for single posts |
| posts_bulk.py | Batch operations (publish, tags, featured) |
| tags_manage.py | CRUD operations for tags |
Ghost uses NQL for filtering:
# Status
status:draft
status:published
status:scheduled
# Tags (use slug, not name)
tag:news
tags:[news,tutorial]
# Featured
featured:true
# Combine (AND)
status:published+featured:true
# Combine (OR)
status:draft,status:scheduled
Note: The --tag option in posts_browse.py accepts both tag names and slugs. It automatically resolves names to slugs via API lookup.
When creating posts from markdown files (e.g., a blog series):
import markdown
from ghost_core import api_request
# 1. Convert Markdown to HTML
md_content = open('article.md').read()
html_content = markdown.markdown(md_content, extensions=['extra', 'nl2br'])
# 2. Create post with source=html (CRITICAL for Ghost 5.0+)
post_data = {
'title': 'My Post',
'html': html_content,
'status': 'draft',
'tags': ['my-tag']
}
response = api_request('POST', 'posts/',
data={'posts': [post_data]},
params={'source': 'html'}) # Required!
Important: Ghost 5.0+ uses Lexical editor format. The source=html param tells Ghost to convert HTML to Lexical. Without it, post content will be empty!
If markdown files have internal links like [Title](other-file.md), replace them with Ghost slugs after creating posts:
LINK_MAP = {
'old-file.md': '/new-ghost-slug/',
}
html = html.replace('href="old-file.md"', 'href="/new-ghost-slug/"')
Bulk operations: Preview mode by default
Delete operations: Require --confirm flag
API versioning: Uses Ghost v5.0 API
HTML conversion: Auto-adds source=html param for Ghost 5.0+ compatibility
cd .claude/skills/ghost-blog/scripts
uv venv
uv pip install -r requirements.txt
cd .claude/skills/ghost-blog/scripts && uv run pytest -v
cd .claude/skills/ghost-blog/scripts && uv run pytest -v --cov=. --cov-report=term-missing
| Error | Cause | Solution |
| ---------------------------------- | -------------------------- | --------------------------------------------- |
| "No virtual environment found" | Missing venv | Run uv venv in scripts directory |
| "Failed to spawn: pytest" | Missing deps | Run uv pip install -r requirements.txt |
| "GHOST_URL not set" | Missing .env | Copy .env.example to .env and configure |
| "GHOST_ADMIN_KEY invalid format" | Wrong key format | Key must be id:secret format |
| "UnauthorizedError" | Invalid API key | Check key is valid and has permissions |
| "UPDATE_COLLISION" | Post modified | Retry operation (auto-refetches updated_at) |
| Post content empty | Missing source=html | Ghost 5.0+ requires source=html param |
| Tag filter returns 0 | Using name instead of slug | Use tag slug or let script resolve it |
| HTTP 422 on tags list | Invalid params | Don't use include=count.posts or order |
| Links point to .md files | Internal markdown links | Replace with Ghost slugs after creating posts |
Ghost Admin API Docs
NQL Filter Reference
tools
Viết/rà soát/tách user story, acceptance criteria, INVEST, epic, backlog từ requirement/PRD/bug/feature.
tools
Phân tích quyết định/vấn đề bằng Thu Giang Nguyễn Duy Cần: Thuật Tư Tưởng, Dịch Lý, Lão Trang, quân bình.
tools
Phân tích tình huống bằng Kinh Dịch: 64 quẻ, Âm Dương, Ngũ Hành, thời, biến, quân tử.
research
Tạo proposal/đề án có research, business case, technical solution. Trigger: RFP, bid, draft proposal, đề xuất dự án.