I got tired of writing throwaway Node scripts every time I needed to create or publish a Ghost post programmatically. So I wrapped the Ghost Admin API in a zero-dependency CLI.
Install
npm install -g @abeedoo/gho
Setup
Create a .gho file in your project with your Ghost Admin API credentials:
GHOST_URL=https://your-site.com
GHOST_ADMIN_API_KEY=your-id:your-secret
Get the key from Ghost Admin → Settings → Integrations → Add custom integration.
What It Does
gho list posts # list all posts
gho list posts --status draft # drafts only
gho draft my-slug "Title" post.md # create draft from markdown
gho publish my-slug # publish it
gho unpublish my-slug # back to draft
gho update my-slug updated.md # update content
gho get my-slug # show post details
gho delete my-slug # delete
gho tags # list tags by usage
That's the whole API. No subcommands to memorize, no config generators, no interactive prompts.
Multi-Site
The .gho file supports [section] headers for managing multiple Ghost instances:
GHOST_URL=https://myblog.com
GHOST_ADMIN_API_KEY=id:secret
[staging]
GHOST_URL=https://staging.myblog.com
GHOST_ADMIN_API_KEY=id:secret
[client]
GHOST_URL=https://client-blog.com
GHOST_ADMIN_API_KEY=id:secret
gho --site staging list posts
gho --site client publish new-post
Why "gho"?
The official ghost-cli npm package manages Ghost instances — installing, starting, stopping, updating the server. This tool manages Ghost content — posts, pages, tags. Different job, different name. gho is three letters and doesn't collide with anything.
Zero Dependencies
The entire thing is one file. It constructs JWTs with Node's built-in crypto module and hits the Ghost Admin API with fetch. No jsonwebtoken, no axios, no SDK. Node 18+ required (for native fetch).
How I Actually Use It
This blog runs on Ghost. I write posts in markdown files in a drafts/ directory. When I'm ready:
gho draft my-post "Post Title" drafts/my-post.md
# review on site...
gho publish my-post
This post was created and published using gho.
npm install -g @abeedoo/gho