Make publishing a required step of the weekly-review skill

Adds step 8 ("Publish to Ghost") so the skill no longer stops at "file
saved to disk" — generating and publishing are one workflow, not two.
Replaces the speculative "Future: Publishing via Ghost Admin API"
section with the operational contract for the now-existing
publish_to_ghost.py script. Updates the slug reference in prose to
match the script (default-newsletter), adds Robotics to the trigger
list, and fixes a stray quote on the robotics/ table row.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Samantha Atkins 2026-05-13 01:30:11 -04:00
parent 6a3b93267d
commit d6f049b08b

View file

@ -1,7 +1,7 @@
--- ---
name: weekly-review name: weekly-review
description: Use this skill when the user asks to generate a "weekly review", create a "review article", run the "weekly review" process, or mentions generating content for AI, Intelligence Augmentation, Longevity, Resource Abundance, Energy, or Space subjects on their scheduled days. description: Use this skill when the user asks to generate a "weekly review", create a "review article", run the "weekly review" process, or mentions generating content for AI, Intelligence Augmentation, Longevity, Resource Abundance, Energy, Space, or Robotics on their scheduled days. The skill generates the article AND publishes it to Ghost — publishing is part of the skill, not a separate step the user must request.
version: 1.3.1 version: 1.4.4
--- ---
# Weekly Review Article Generator # Weekly Review Article Generator
@ -84,7 +84,7 @@ Generate weekly review articles covering the best 10 items from the past week in
| `resource-abundance/` | Resource Abundance | | `resource-abundance/` | Resource Abundance |
| `energy/` | Energy | | `energy/` | Energy |
| `space/` | Space | | `space/` | Space |
| 'robotics/' | Robotics | | `robotics/` | Robotics |
@ -128,7 +128,8 @@ Source: [Publication Name](url)
7. **Save the article** 7. **Save the article**
- Write to the appropriate subject directory - Write to the appropriate subject directory
- Confirm completion with the filename
8. **Publish to Ghost** — run the script described in "Publish via Ghost Admin API" below. This step is not optional. Do not ask the user for confirmation; do not stop after step 7. The skill is not complete until the script has exited successfully. If the script exits non-zero, report the error to the user; otherwise report the published URL.
## Writing Style ## Writing Style
@ -139,62 +140,23 @@ Source: [Publication Name](url)
- Connect items to broader trends and implications - Connect items to broader trends and implications
- When a claim depends on a specific number or date, attribute it to a source rather than presenting it as established fact - When a claim depends on a specific number or date, attribute it to a source rather than presenting it as established fact
## Future: Publishing via Ghost Admin API ## Publish via Ghost Admin API
This skill's scope ends at "file saved to disk." A separate publisher script handles the Ghost API integration. Documenting the contract here so the invariant doesn't drift. Publishing is handled by `publish_to_ghost.py` in this skill directory. It mints a short-lived JWT from the Ghost Admin API key (returned by `pass show fulfillment/api-key` in `id:secret` form), strips the leading H1 from the article, converts the rest to HTML with pandoc, and runs Ghost's required two-step draft-then-publish flow so the newsletter email is sent.
### The invariant Invoke it with the article path:
The filename-to-title chain established above extends naturally into publishing:
- Filename stem (minus `.md`) → Ghost `title` field in the API body
- First H1 of the markdown → same string, duplicated for local readability
- Everything after the first H1 → Ghost post body (HTML-converted, first H1 stripped)
The Ghost newsletter slug is a separate piece of configuration — a single value identifying which newsletter in Ghost Admin the post should be emailed through. Pipeline-level config, not per-file. Each newsletter must be created once in Ghost Admin (Settings → Email newsletter → Newsletters) before the first automated publish; the API cannot create newsletters.
### Two-step publish pattern
Ghost's Admin API requires a draft-then-publish flow to trigger newsletter email send. Single POST with `status: published` and a `newsletter` query parameter silently publishes without emailing. Confirmed pattern:
**Step 1 — create draft:**
```
POST /admin/posts/?source=html
Body: {
"posts": [{
"title": "<filename stem>",
"html": "<body HTML, first H1 stripped>",
"status": "draft",
"newsletter": "<newsletter-slug>"
}]
}
```
Response contains `id` and `updated_at` — capture both.
**Step 2 — publish and send:**
```
PUT /admin/posts/<id>/?newsletter=<newsletter-slug>&email_segment=all
Body: {
"posts": [{
"updated_at": "<from step 1 response>",
"status": "published"
}]
}
```
The `newsletter` query parameter must be on both requests. `email_segment=all` sends to all subscribers; `status:free` or `status:-free` target free-only or paid-only.
Do NOT set `email_only: true` — that suppresses the public blog post and sends email only. Weekly reviews should appear on both the blog and in email.
### Body transformation
The markdown on disk starts with an H1 that duplicates the Ghost `title`. Strip it before converting to HTML and sending, otherwise Ghost renders the title twice:
```bash ```bash
title=$(basename "$file" .md) python3 <skill-dir>/publish_to_ghost.py <subject-directory>/<article.md>
body=$(tail -n +2 "$file" | sed '/./,$!d') # drop first line, then leading blanks
html=$(echo "$body" | pandoc -f markdown -t html)
``` ```
### Validation The newsletter slug (`default-newsletter`) is a constant at the top of the script. There is one newsletter for the whole publication. If you ever split into per-subject or per-section-frame newsletters, change `NEWSLETTER_SLUG` in the script — or promote it back to a CLI argument and add a per-subject mapping here.
Pipeline invariants the script enforces:
- The filename stem becomes the Ghost `title` field. The first H1 of the markdown is the same string, duplicated for local readability, and is stripped before HTML conversion so Ghost doesn't render the title twice.
- Draft-then-publish is required to trigger newsletter send. A single POST with `status: "published"` silently publishes without emailing.
- `email_only: true` is deliberately NOT set — weekly reviews appear on both the blog and in email.
The script exits non-zero with the HTTP body on any API failure.
Before publishing, the publisher should verify that the first H1 of the file matches `basename "$file" .md`. This catches rename/edit drift — cases where the filename was changed but the H1 wasn't, or vice versa. If the check fails, refuse to publish and surface the mismatch.