Finalize the current blog post -- build, commit, push, open PR, and clean up the worktree.
You are finalizing a blog post. Follow these steps exactly.
Check that we are in a git worktree on a post/* branch:
git rev-parse --show-toplevel
git branch --show-current
If the current branch does not start with post/, warn the user and ask whether to continue.
Extract the slug from the branch name:
SLUG=$(git branch --show-current | sed 's|^post/||')
Identify the post file by finding the markdown file(s) that differ from main:
git diff main --name-only -- 'src/content/blog/*.md'
Store the post file path as POST_FILE. If multiple files changed, list them and ask which one is the post being shipped.
Check for and delete any research scratchpad file:
rm -f "src/content/blog/${SLUG}-research.md"
This file is gitignored, but remove it explicitly so it doesn't linger in the worktree.
Run the fact-check and style-check agents in parallel against the post file. Present their findings to the user before continuing. If either agent reports "must fix" items, ask the user whether to address them now or ship as-is.
Read POST_FILE and check:
--- (not just empty or whitespace).If either check fails, warn the user: "This post looks empty or very short. Continue anyway?"
Scan the post body for markdown image references () and check that each referenced file exists at the path relative to the project root (for paths starting with /, check in public/).
If any referenced images are missing, warn the user:
These images are referenced in the post but don't exist:
/blog/<slug>/missing-file.svgContinue anyway, or fix the references first?
Stage the post file and any assets in the post's public directory:
git add "src/content/blog/${SLUG}.md"
if [ -d "public/blog/${SLUG}" ]; then
git add "public/blog/${SLUG}/"
fi
git add -A
git status --porcelain
If there are staged changes, commit them:
git commit -m "docs: finalize post content"
Run the build command:
npm run build
If the build fails:
DRAFT_PR=true and continue.If the build succeeds, set DRAFT_PR=false.
Shipping means publishing. Change draft: true to draft: false in the frontmatter (or remove the draft line entirely since the schema defaults to false). Do not ask, just do it.
Stage and commit:
git add "$POST_FILE" && git commit -m "docs: mark post as published"
Extract the title and description from the post frontmatter for the PR.
BRANCH=$(git branch --show-current)
git push -u origin "$BRANCH"
Build the gh pr create command:
--title = post title from frontmatter--body = PR description that includes the post's description field and a brief summaryDRAFT_PR=true (build failed), add --draftgh pr create --title "$TITLE" --body "$(cat <<'EOF'
## New Blog Post
**Description:** <post description from frontmatter>
**Summary:** <1-2 sentence summary of what the post covers>
Generated with [Claude Code](https://claude.com/claude-code)
EOF
)"
Capture and store the PR URL from the output.
Store the current worktree path, then cd back to the main repo:
WORKTREE_PATH=$(git rev-parse --show-toplevel)
MAIN_REPO=$(git worktree list --porcelain | head -1 | sed 's/worktree //')
cd "$MAIN_REPO"
git worktree remove "$WORKTREE_PATH"
If removal fails, tell the user:
Automatic cleanup failed. Run manually:
git worktree remove <path>
Print a summary:
Title: <post title>
Branch: <branch name>
PR: <PR URL>
Status: <"will publish on merge" or "draft -- won't publish yet">