Blog Draft
Draft a blog post for codyanthony.dev/blog/ from an approved blog-plan blueprint. Executes the motivating question, violated expe…
---
description: Draft a blog post for codyanthony.dev/blog/ from an approved blog-plan blueprint. Executes the motivating question, violated expectation, architecture, reader movement, evidence map with collision events, personal-tone voice, and ai-antipatterns style guide into a ready-to-merge draft. Interactive flow with branch management, proposals, series support, deterministic-script validation, and optional commit/deploy.
version: 1.2
---
---
# /blog-draft
Executes an approved blueprint from `/blog-plan` into a ready-to-merge draft. The motivating question, violated expectation, central claim, architecture, reader movement, anchor story, evidence map with collision events, beat outline, opener shape, working title, slug, and links are already decided and validated in the plan. This command does not re-plan. Eight phases: Setup → Blueprint → Proposals → Compose → Validate → Review → Save → Ship. Each phase gates on user confirmation; the deterministic script runs before LLM judgment during validation.
> **Running blog-draft v1.2** — Skill load + verification gate → branch management → load the blueprint (`.claude/plans/{slug}.md`) + confirm remaining metadata → confirm proposals (title, slug, blueprint summary, tags) → compose direct to file → deterministic + LLM validation → user review → deterministic save gates → optional commit/deploy.
> Run `/blog-plan` first. It produces the blueprint this command consumes. Starting here without one is only for a simple post with one obvious example; anything with real architecture should be planned first.
Print the banner above verbatim before doing anything else. Then print:
> Type `cancel` at any point to exit. Files already written will be preserved with `draft: true` in frontmatter — re-run `/blog-draft` on the same slug to resume.
## Dependencies
**Required skills (must load before drafting begins):**
- `.claude/skills/ai-antipatterns/SKILL.md` — universal negative style guide (canonical)
- `.claude/skills/personal-tone/SKILL.md` — voice, brand alignment, audience layering
- `.claude/skills/blog-post-framework/SKILL.md` — three-beat content checks, opener shapes, structural integrity
- `.claude/skills/blog-checklist/SKILL.md` — pre-publish gates
- `writer-context` (**global skill, not in this repo**) — verified work history, role specifics, NDA/proprietary reference guidance, common overclaims to refuse. Personal to the writer, so it lives at `~/.claude/skills/writer-context/` rather than in the repo; load it by name via the Skill tool.
**Loaded conditionally (in Phase 1b if the blueprint marks the post series-participating):**
- `.claude/skills/series-blocks/SKILL.md` — intro/navigation block templates
**Required scripts:**
- `scripts/check-blog-prose.mjs` — deterministic prose validation
OG images are no longer generated as a build step: the social card is rendered
on demand by the `/og/[slug].png` endpoint and cached to R2 on first scrape (see
Phase 6). No `generate-blog-og.mjs` / static PNG.
**Required tools:** Read, Write, Bash, Edit. Bash for git operations, script invocation, file existence checks, and `pnpm astro check`.
---
## Phase 0: Setup
### 0a. Skill loading and verification gate
Load the project-local skills (`ai-antipatterns`, `personal-tone`, `blog-post-framework`, `blog-checklist`, and conditionally `series-blocks`) via Read at their `.claude/skills/<name>/SKILL.md` paths — project-local auto-discovery via the Skill tool can be session-dependent, so Read is the reliable path for these. Load `writer-context` via the Skill tool **by name**: it is a global, writer-personal skill (`~/.claude/skills/writer-context/`) that lives outside the repo, and global skills surface reliably by name. If `writer-context` fails to load, stop and report — do not draft claims about the writer without it.
Confirm each skill is loaded by listing one key rule from each in this format:
```text
Skills loaded:
[x] ai-antipatterns — "Zero em dashes in prose (description lists / link lists exempt)"
[x] personal-tone — "Audience layering: peers primary, recruiters always reading too"
[x] blog-post-framework — "Three beats are content checks, not section templates"
[x] blog-checklist — "Deterministic gate runs check-blog-prose.mjs before LLM judgment"
[x] writer-context — "Refuse 'founding writer for ROSA' (he joined post-GA); refuse 'inherited' framing for AWS XML migration"
Do not proceed past this gate until all five skills are confirmed in context. If any failed to load, report which one and stop.
0b. Branch management
Detect current branch:
CURRENT_BRANCH=$(git -C . branch --show-current)
echo "Current branch: $CURRENT_BRANCH"
If CURRENT_BRANCH is main: drafting on main is not allowed without explicit override. Prompt:
Current branch: main
Drafting on main is not recommended — feature branches keep production
deploy safety and let you preview without affecting the live site.
Options:
setup Create a feature branch (named blog/wip-{YYYY-MM-DD}; renamed to blog/{slug} in Phase 2)
continue Proceed on main (you'll need to manage commits and deploy carefully)
cancel Exit
Wait for response.
setup: if working tree has uncommitted changes, promptstash / commit / discard / cancel. After resolution, run:git -C . checkout main git -C . pull origin main git -C . checkout -b "blog/wip-$(date +%Y-%m-%d)"This branch will be renamed to
blog/{slug}in Phase 2 once the slug is chosen.continue: proceed on main, print warning.cancel: exit.
If CURRENT_BRANCH starts with blog/: existing feature branch. Ask:
On existing feature branch: {branch}
Options:
continue Use this branch (draft will save to this branch)
new Create a new blog/wip-{date} branch off main
cancel Exit
If CURRENT_BRANCH is any other branch: ask:
On branch: {branch}
Options:
stay Stay on this b
Maintain Blog Draft?
Let people know it's listed here — add the badge (live metrics, light/dark aware) or a plain link to your README or docs.
[Blog Draft on getagentictools](https://getagentictools.com/loops/codyanthony-blog-draft?ref=badge)