This library provides a complete workflow for publishing org-mode files to Ghost CMS with rich media support. The workflow separates concerns into distinct phases:
| Phase | Purpose | Speed | Interactive |
|---|---|---|---|
| Generate | Create media (TTS, images, video) | Fast | Yes, iterate |
| Enrich | Add metadata to media/embeds | Slower | Once |
| Preview | View HTML locally | Fast | Yes |
| Publish | Send to Ghost | Fast | Once |
(add-to-list 'load-path "/srv/research/org/ox-ghost")
(require 'ghost-publish)
;; Configure Ghost connection
(setq ghost-publish-url "https://www.ii.coop"
ghost-publish-admin-key "YOUR_ADMIN_API_KEY")Generation functions create media files, upload them to Ghost, and return basic org syntax. Run these iteratively while developing your post.
#+CALL: ghost-tts("Welcome to my tutorial")
Returns:
Welcome to my tutorial
#+CALL: ghost-image("Chapter One" "#e74c3c" "#c0392b")
Returns:
[[https://ghost.site/content/images/2026/01/img-xxx.png][Chapter One]]
#+CALL: ghost-video("Org Mode Powers This" "#2d3436")
Returns:
Org Mode Powers This
#+CALL: ghost-upload("/path/to/file.png")
Returns the Ghost URL for the uploaded file.
Once content is stable, enrich adds metadata required by Ghost’s Lexical format. This is a separate step because:
- Enrichment involves HTTP requests (slower)
- You don’t want to re-fetch metadata on every iteration
- You can review enriched content before publishing
| Command | Description |
|---|---|
M-x ghost-enrich-buffer | Enrich all blocks in current buffer |
M-x ghost-enrich-region | Enrich blocks in selected region |
M-x ghost-enrich-at-point | Enrich single block at cursor |
| Block Type | Added Metadata |
|---|---|
| VIDEO | :width, :height, :duration, :mimeType, :thumbnailSrc |
| AUDIO | :duration, :mimeType |
| EMBED | :html (iframe code for YouTube/Vimeo) |
| BOOKMARK | :title, :description, :icon, :thumbnail |
My video description First YouTube video
My video description First YouTube video
Preview renders the org file to HTML without publishing, so you can verify appearance locally.
| Command | Description |
|---|---|
M-x ghost-preview | Export to HTML, open in browser |
M-x ghost-preview-json | Export to Lexical JSON, view in buffer |
When satisfied with preview, publish to Ghost.
| Command | Description |
|---|---|
M-x ghost-publish | Create new post (draft) |
M-x ghost-update | Update existing post |
M-x ghost-publish-and-open | Publish and open in browser |
1. Create org file with content
#+TITLE: My Tutorial
#+TAGS: tutorial, demo
* Introduction
#+CALL: ghost-tts("Welcome to my tutorial")
* Main Content
#+CALL: ghost-image("Step One" "#667eea" "#764ba2")
...
2. Iterate on generation
- C-c C-c on blocks to regenerate
- Preview inline results
- Adjust text, colors, etc.
3. Enrich when satisfied
M-x ghost-enrich-buffer
- Review the added metadata
- Verify blocks look correct
4. Preview locally
M-x ghost-preview
- Opens HTML in browser
- Check layout, media playback
5. Publish
M-x ghost-publish
- Creates draft on Ghost
- Returns URL for review
#+TITLE: Post Title #+DATE: 2026-01-29 #+AUTHOR: ii.coop #+TAGS: tag1, tag2, tag3 #+EXCERPT: Brief description for previews and SEO.
| Use Case | Recommended Block |
|---|---|
| Important callout | #+BEGIN_CALLOUT :emoji |
| Collapsible content | #+BEGIN_TOGGLE |
| External video | #+BEGIN_EMBED :url |
| Uploaded video | #+BEGIN_VIDEO :src |
| Audio player | #+BEGIN_AUDIO :src |
| Link preview | #+BEGIN_BOOKMARK :url |
| Call to action | #+BEGIN_BUTTON :url |
- TTS: Keep text concise (under 20 words per block)
- Images: Use contrasting gradient colors for readability
- Video: Keep under 10 seconds for concept demos
Standard gradients for consistency:
| Purpose | Start | End |
|---|---|---|
| Info | #667eea | #764ba2 |
| Warning | #f39c12 | #e74c3c |
| Success | #00b894 | #00cec9 |
| Dark | #2d3436 | #636e72 |
External tools required:
| Tool | Purpose | Install |
|---|---|---|
| espeak-ng | Text-to-speech | dnf install espeak-ng |
| ffmpeg | Audio/video processing | dnf install ffmpeg |
| ffprobe | Media metadata | (included with ffmpeg) |
| magick | Image generation | dnf install ImageMagick |
| curl | HTTP requests | (usually pre-installed) |
| node | Ghost API client | dnf install nodejs |
┌─────────────────────────────────────────────────────────┐
│ Org File (.org) │
│ #+TITLE, content, #+CALL: ghost-* functions │
└─────────────────────────────────────────────────────────┘
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌─────────┐
│ Generate│ │ Enrich │ │ Preview │
│ (iterate)│ │ (once) │ │ (local) │
└─────────┘ └──────────┘ └─────────┘
│ │ │
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌─────────┐
│espeak-ng│ │ ffprobe │ │ Browser │
│ ffmpeg │ │ curl │ │ │
│ magick │ │ │ │ │
└─────────┘ └──────────┘ └─────────┘
│ │
└────────┬─────────┘
▼
┌─────────────────┐
│ ghost.js │
│ (upload/publish)│
└─────────────────┘
│
▼
┌─────────────────┐
│ Ghost CMS │
└─────────────────┘