What Is This, and Why Did I Build It?
I read a lot. I also write about what I read — but the gap between finishing a book and actually publishing a polished blog post used to span days of friction: open a file, write a summary from scratch, fiddle with HTML, copy-paste into my site, push to GitHub. Every step was manual, every step was a chance to procrastinate.
So I automated it. The Blog Automation project is a Node.js pipeline that strings
together four concerns — book selection, AI content generation, HTML templating, and GitHub publishing —
into one command. The pipeline lives at src/index.js and is driven entirely by
configuration and environment variables, making it trivial to extend to new content types.
The whole thing is deployed as a Vercel Serverless Function and fired automatically
by a Vercel cron job — zero manual intervention once it's set up.
The Pipeline — Four Steps, One Command
The entry point (src/index.js) orchestrates four discrete modules. Each module owns
exactly one responsibility, which keeps the code easy to test and swap out independently.
Locally you can run it manually; in production it's invoked by Vercel on a schedule.
# Install once
npm install
# Create .env with your tokens (local dev)
HF_TOKEN=hf_your_token_here
GITHUB_OWNER=your_github_username
GITHUB_REPO=your_repo_name
GITHUB_TOKEN=github_pat_123...
# Run the full pipeline locally
node src/index.js
Step 1 — Book Selection (src/books.js): Reads a curated list of books
and picks one at random. Critically, it then permanently removes that entry from the list,
so the same book can never be published twice. This is a deliberately destructive write — it's the
simplest possible deduplication strategy and it works perfectly for this use-case.
Step 2 — Prompt Construction (src/promptBuilder.js): Takes the selected
book's metadata and builds a structured prompt for the language model. The prompt instructs the LLM
to produce a specific JSON shape — title, subtitle, TL;DR bullets, sections — that the template
engine can consume directly without any post-processing guesswork.
Step 3 — AI Generation (src/hfClient.js): Sends the prompt to the
Hugging Face Inference API. The model and endpoint are configurable via src/config.js,
so swapping to a different model is a one-line change. The client handles retries and surfaces
meaningful errors if the API key is missing or rate-limited.
Step 4 — Template + Publish (src/templateEngine.js & src/github.js):
The AI response is injected into templates/Books-Template.html by replacing named
placeholders. The rendered HTML is then pushed to the GitHub repository via the GitHub Contents API,
which triggers a GitHub Pages deploy automatically — no manual git push needed.
Deployed on Vercel, Triggered by a Cron Job
The pipeline function is deployed to Vercel Serverless Functions. Vercel's
vercel.json config defines a cron schedule that hits the function endpoint at a set
interval — no always-on server, no EC2 instance, no manual babysitting. Vercel spins up the
function, runs the full pipeline, and tears it down. The only infrastructure cost is the function
execution time, which for this workload is negligible.
// vercel.json
{
"crons": [
{
"path": "/api/run-pipeline",
"schedule": "0 9 * * 1"
}
]
}
The schedule above fires every Monday at 9 AM UTC. Vercel calls
/api/run-pipeline, which executes the full select → generate → template → publish
flow. All secrets — HF_TOKEN, GITHUB_TOKEN — are stored as Vercel
environment variables, so nothing sensitive ever lives in the repo.
// hot take Serverless + cron is the most underrated combo in indie dev. You get scheduled automation with zero infrastructure overhead — and Vercel makes it a three-line config. The hard part was never the deployment; it was building a pipeline worth deploying. — Shweta Suryavanshi
What I'd Do Differently (and What's Next)
The current pipeline is intentionally minimal — it does one thing end-to-end and does it reliably.
If I were to scale this up, I'd introduce a proper queue (even a simple JSON file with a
status field) so that failed runs can be retried without re-consuming the book from the
list. I'd also add a dry-run mode that writes the generated HTML to a staging branch for review
before the cron job merges it to main and triggers the GitHub Pages deploy.
The next content type I want to automate is tech news recaps — weekly roundups generated from a
curated list of RSS feeds, summarised by an LLM, and published on a separate cron schedule via
Vercel. The module structure already makes this straightforward: swap books.js for an
RSS reader, update the prompt template, point the template engine at the tech-news HTML template,
and add a second entry to vercel.json crons. The GitHub publisher and the config layer
don't need to change at all.