The blog uses a publishAt frontmatter field to support soft embargoes: post deploys to Vercel immediately on merge but is hidden from the blog index (/blog listing) until publishAt passes. The index revalidates hourly.
Without this field, posts are indexed immediately on deploy. If social posts aren't already in Buffer before the merge, you get a window where the post is live but no social amplification is queued.
This skill coordinates the three moving parts:
publishAt in MDX frontmatter (blog index gate)--publish-at in convert-to-mdx.py (how to set it)publishAt + 15 min (social timing)> Blog index visibility and social posts must be coordinated. Always decide publishAt before raising the PR.
| Scenario | publishAt | Buffer timing |
|---|---|---|
| --- | --- | --- |
| Want coordinated launch (blog + social together) | Set to future slot | Schedule Buffer at publishAt + 15 min |
| Post can go live now, social later same day | Set to now + 30 min | Schedule Buffer at publishAt + 15 min |
| No embargo needed (emergency fix, no social) | Omit or set to now | Post immediately |
Before raising the PR, decide a specific AEST datetime:
publishAt = "2026-04-04T09:00:00+11:00" # AEDT
publishAt = "2026-04-04T09:00:00+10:00" # AEST
Pass --publish-at to convert-to-mdx.py:
python3 scripts/blog/convert-to-mdx.py \
--input projects/blog-pipeline/converted/<slug>.md \
--output projects/blog-pipeline/converted/<slug>.mdx \
--slug <slug> \
--title "<title>" \
--description "<description>" \
--tags "<tags>" \
--author "Nissan Dookeran" \
--publish-at "2026-04-04T09:00:00+11:00"
Check: MDX frontmatter should contain publishAt: "2026-04-04T09:00:00+11:00".
Post deploys immediately. Direct URL (/blog/slug) resolves. Blog index (/blog) hides the post until publishAt.
After merge, schedule social posts with dueAt = publishAt + 15 min:
# X/Twitter — at publishAt + 15 min
node scripts/buffer-post.mjs \
--text "$(cat projects/social-growth/thread-<slug>.md | ...)" \
--channel twitter \
--publish-at "2026-04-04T09:15:00+11:00"
# LinkedIn — same time or later slot
node scripts/buffer-post.mjs \
--text "$(cat projects/social-growth/linkedin-<slug>.md | ...)" \
--channel linkedin \
--publish-at "2026-04-04T09:15:00+11:00"
Or use the batch file approach with scripts/buffer-post.mjs --file posts.json.
If a post was merged without publishAt and is already indexed:
This happened with:
ollama-embeddings (2026-04-03) — live, no social queuedportkey-patterns (2026-04-03) — live, no social queuedpublishAt is an ISO8601 field added to MDX frontmatter/blog) filters posts where publishAt > nowexport const revalidate = 3600 means the index updates hourly/blog/slug) always resolves — no gate at the page levelconvert-to-mdx.py sets both publishAt and aligns the date field when --publish-at is providedplaybooks/blog-publish/PLAYBOOK.md — Step 0b (Embargo Gate) uses this skillscripts/blog/convert-to-mdx.py — --publish-at flagscripts/buffer-post.mjs — --publish-at flag or publishAt in batch JSON69c29939af47dacb694d3d1f, LinkedIn 69c29382af47dacb694d24b42026-04-03: Two posts (ollama-embeddings, portkey-patterns) merged without publishAt. Both immediately indexed. Social copy existed but hadn't been approved yet, so nothing was in Buffer. Result: posts live with no social amplification window. Fix: this skill + mandatory Step 0b in blog-publish playbook.
共 1 个版本