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.
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.

