Everything I post here goes out through blog-kit: a small publisher for the dev.to API, a diagram renderer, and a cover maker. The bit I wouldn't post without is the leak check. My drafts start life full of real addresses and hostnames from my notes, and one slipping into a public post is the kind of mistake you only make once.

Five minutes to set up, and the guide is run on a fresh Ubuntu machine every week.

blog-kit on a fresh GitHub runner: a dry run of a real draft, the leak check refusing a private IP, and a diagram rendered to PNG

Dry run

Python 3 and the standard library, that's it.

git clone https://github.com/casareanderson/blog-kit.git && cd blog-kit python3 publish.py drafts/devto-05-buzzwords.md 

It prints the title, tags and word count and ends with dry run — nothing sent. Add --publish when you mean it. Every run is a dry run unless you say otherwise. No key needed.

The leak check

Put a private address in a post and try:

⚠️ the leak check found: - a private IP: 10.1.2.3 refusing to publish. Genericise it, or pass --force. 

It looks for private IP ranges, API keys and password=-style secrets, and it refuses even on a dry run. Swap real addresses for documentation ones like 192.0.2.x.

Publish

export DEVTO_API_KEY=... python3 publish.py drafts/my-post.md --publish 

After posting it reads the article back from dev.to and prints published_at. I added that because dev.to's create response says published: null even when it worked, which reads like a failure.

Diagrams

sudo apt install librsvg2-bin ./diagram.sh assets/internal-tool/01-glue.svg 

Draw at 880px wide, render at 1760 so it's sharp. Give the SVG a white background: dev.to has a dark mode, and dark text on a transparent PNG vanishes in it.

What CI can't prove

Publishing (needs your key) and covers (need a ComfyUI server and push access to a repo). The weekly run stops at the point of sending.

Full guide: github.com/casareanderson/blog-kit/blob/main/docs/SETUP.md

How do you keep real hostnames and IPs out of what you publish?

🤖 Drafted with AI assistance from my own homelab notes, logs and repos, then reviewed and edited before publishing.