Jake Rosow
Workflow Automation Case Study
case-study · gifted-blog-automation

Blog Automation Workflow

A GitHub Actions job that picks a topic out of the course textbook, drafts the post, checks it, and publishes only when git sees a real change.

Role
Workflow designer + builder
Status
Live
Started
2026-06
URL
gifted-academics.com/blog ↗
Source
Private · GitHub Action + live blog + generated post metadata
the workflow

Every run passes the gates or publishes nothing.

01

Trigger

  1. 01
    Cron route

    Bearer CRON_SECRET protects the Vercel endpoint.

  2. 02
    Dispatch

    GitHub API starts blog-post-auto.yml with a Monday UTC slot.

02

Generate

  1. 01
    Rotate cert

    State picks TSAC-F, CSCS, NASM CPT, or CISSN.

  2. 02
    Screen topic

    Table of contents (TOC) ranges, slug tokens, and source overlap reject repeats.

  3. 03
    Draft

    OpenRouter writes from source text, style guide, template, and schema.

03

Publish

  1. 01
    Validate

    Frontmatter, links, sections, definitions, and word count must pass.

  2. 02
    Cover

    Pexels image and attribution attach when a match is found.

  3. 03
    Commit

    Commits content/blog-posts only when git sees a diff.

hiring signal
What this proves

I can put AI generation inside a job you can audit afterwards, down to which pages it read and which titles it threw away.

Risk handled

Automated content wanders off topic, repeats itself, or quietly runs twice for the same week.

Evidence

Every run leaves a trace file: which week it filled, which textbook pages it drew from, which titles it rejected, and what the repeat check scored.

live screens

Blog index and generated post.

Generated post detail: the frontmatter, cover image, metadata, and Markdown all made it through the publish path.

A weekly blog generator for Gifted Academics. It picks a certification topic, pulls bounded source material from the matching textbook, drafts a Markdown post through OpenRouter, validates the result, adds a cover image, writes a trace file, and lets GitHub publish the diff.

Why it exists

The business needed regular certification-prep articles without making every post a manual project. The point was never volume for its own sake. It was search traffic that stayed tied to real exam categories and to topics the textbook could actually back up.

I built around that constraint. The system chooses from the course source material first, then asks the model to write inside a tight template. The publish path is a git diff, not a hidden CMS mutation.

What made it hard

Blog automation fails quietly if the only check is "did the model return text?" A generated article can repeat an old topic, make claims the textbook does not support, leave out the link back to the course, or run twice for the same week.

The prompt sits in the middle of the run. Before drafting, the generator works out which Monday it is filling and picks the next certification in the rotation. Then it chooses a range of textbook pages, pulls enough prose out of them, and checks that range has not been used before. After drafting, it validates the Markdown and retries once with specific feedback before writing files.

What the workflow leaves behind

Each generated post gets an automation.json file: slot, cert, selected slug, source file, textbook line ranges, rejected candidate titles, model, novelty judgment, workflow run URL, and cover metadata. That file makes the article easier to inspect after the fact.

The latest generated post on the live blog came from the June 22, 2026 slot. Its trace recorded a CISSN source range, novelty confidence of 0.88, the OpenRouter model used for drafting, and the Pexels photo attribution that appears in the rendered article.

decisions

What the gates are for.

GitHub Actions is the publisher

Chose

GitHub Actions checks out main, installs the app, runs the generator, commits content/blog-posts when there is a diff, and pushes back to main.

Why

The blog is file-backed content. Publishing through git leaves a run URL, a reviewable diff, and a history you can roll back.

Cost

The action needs write permissions and production secrets. A bad generator change can publish directly unless the gates catch it first.

Pick the topic before asking the model

Chose

The generator rotates through NSCA TSAC-F, NSCA CSCS, NASM CPT, and CISSN. It reads the cached table of contents for each textbook, picks usable page ranges, and throws out weak or repeated candidates before the model sees anything.

Why

The model writes from bounded source material; the content calendar is resolved before it runs. Candidate selection is deterministic, so a run is explainable after the fact.

Cost

The output is only as good as the table-of-contents cache and the line-range heuristics. Messy OCR headings still need rejection rules.

Validate the post, then record why it exists

Chose

Each draft has to pass frontmatter, slug, section, word-count, link, and definition checks. The run also writes automation.json with the source ranges, model, novelty judgment, cover metadata, and rejected candidates.

Why

A generated post has to render cleanly, and I need to be able to audit it later. The trace file explains why that post exists and which source material supported it.

Cost

Validation adds one more repair loop and can turn a run into a no-op. I would rather skip a week than publish a near-duplicate or a broken post.

the stack

The stack.

Want the walkthrough, or the parts that aren’t written up yet?

jakerosow@gmail.com
Up next
Shipit News AI/coding news aggregator