ghost-blog

Manage Ghost blog posts via Admin API. Capabilities include list/filter posts (status, tag, featured, search), CRUD operations (create, read, update, delete, publish), bulk operations (mass publish/unpublish, add/remove tags), and tag management. Use when user mentions ghost blog, manage posts, publish drafts, bulk update, or blog management tasks.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "ghost-blog" with this command: npx skills add hoangvantuan/claude-plugin/hoangvantuan-claude-plugin-ghost-blog

Ghost Blog Management

Manage Ghost CMS posts and tags via Admin API.

Setup

1. Install Dependencies

cd .claude/skills/ghost-blog/scripts
uv venv
uv pip install -r requirements.txt

2. Configure Environment

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:

  1. Go to Ghost Admin → Settings → Integrations
  2. Create a Custom Integration
  3. Copy the Admin API Key (format: id:secret)

3. Verify Setup

cd .claude/skills/ghost-blog/scripts && uv run python ghost_core.py

Quick Start

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"

Dispatch Rules

User IntentScriptExample Command
test, run testspytestcd scripts && uv run pytest -v
list posts, show drafts, filter postsposts_browse.py--status draft --tag news
get post, read post, show postposts_crud.py get--id xxx or --slug xxx
create post, new post, write postposts_crud.py create--title "..." --html "..."
update post, edit post, change postposts_crud.py update--id xxx --title "..."
delete post, remove postposts_crud.py delete--id xxx --confirm
publish post, publish draftposts_crud.py publish--id xxx
unpublish postposts_crud.py unpublish--id xxx
bulk publish, publish all draftsposts_bulk.py publish--filter "..." --execute
bulk unpublishposts_bulk.py unpublish--filter "..." --execute
add tag to posts, tag postsposts_bulk.py add-tag--filter "..." --tag xxx --execute
remove tag from postsposts_bulk.py remove-tag--filter "..." --tag xxx --execute
list tags, show tagstags_manage.py list(no options needed)
create tag, new tagtags_manage.py create--name "..."
delete tag, remove tagtags_manage.py delete--slug xxx --confirm

Scripts

ScriptPurpose
ghost_core.pyShared: JWT auth, HTTP client, error handling
posts_browse.pyList, filter, search posts
posts_crud.pyCRUD operations for single posts
posts_bulk.pyBatch operations (publish, tags, featured)
tags_manage.pyCRUD operations for tags

Filter Syntax (NQL)

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.

Creating Posts from Markdown Files

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!

Fixing Internal Links

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/"')

Safety Features

  • 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

Testing

Setup Test Environment

cd .claude/skills/ghost-blog/scripts
uv venv
uv pip install -r requirements.txt

Run Tests

cd .claude/skills/ghost-blog/scripts && uv run pytest -v

Run with Coverage

cd .claude/skills/ghost-blog/scripts && uv run pytest -v --cov=. --cov-report=term-missing

Troubleshooting

ErrorCauseSolution
"No virtual environment found"Missing venvRun uv venv in scripts directory
"Failed to spawn: pytest"Missing depsRun uv pip install -r requirements.txt
"GHOST_URL not set"Missing .envCopy .env.example to .env and configure
"GHOST_ADMIN_KEY invalid format"Wrong key formatKey must be id:secret format
"UnauthorizedError"Invalid API keyCheck key is valid and has permissions
"UPDATE_COLLISION"Post modifiedRetry operation (auto-refetches updated_at)
Post content emptyMissing source=htmlGhost 5.0+ requires source=html param
Tag filter returns 0Using name instead of slugUse tag slug or let script resolve it
HTTP 422 on tags listInvalid paramsDon't use include=count.posts or order
Links point to .md filesInternal markdown linksReplace with Ghost slugs after creating posts

References

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

creative-thought-partner

No summary provided by upstream source.

Repository SourceNeeds Review
General

prompt-generator

No summary provided by upstream source.

Repository SourceNeeds Review
General

openproject

No summary provided by upstream source.

Repository SourceNeeds Review
General

viral-post-creator

No summary provided by upstream source.

Repository SourceNeeds Review