The problem
Every week I ship things. Features, fixes, refactors. It's all there in git.
But writing a post about it? I'd either skip it entirely or spend 20 minutes staring at a blank box writing something that sounded nothing like me.
I knew what I built. Git knew what I built. The gap was just turning one into the other.
What I built
commitpost — a CLI that reads your git history, sends it to Claude AI, and writes a post in your voice. Optionally generates a cover image with your actual code as the background.
npm install -g commitpost
commitpost generate --include-image
That's it. One command. Post and image ready to copy-paste.
How it works
- Runs
git log --author --sinceto grab your recent commits - Sends them to Claude with your tone profile (a writing sample you set once)
- Generates the post text
- Extracts a real changed file from your commits for the cover image
- Syntax-highlights it, applies blur, overlays the headline
- Outputs a 1200×627px PNG ready for LinkedIn, Bluesky, or X
The interesting technical parts
Cover image without a browser
My first instinct was Puppeteer. Installed it, no Chrome binary. Pivoted to satori (Vercel's JSX→SVG renderer) + @resvg/resvg-js (Rust SVG→PNG) + sharp for compositing.
No headless browser. No Electron. Pure Node, works anywhere.
Blurring code correctly
Blurring sounds simple. It wasn't.
SVG feGaussianBlur clips at element boundaries — above ~sigma 20, no visible effect. Switched to sharp.blur(). But blurring a transparent PNG destroys the alpha channel and the layer disappears entirely when composited.
The fix: render background + code as one solid image first, then blur. Solid pixels blur correctly. Then composite the UI (headline, author) on top as a separate transparent layer.
Code that starts at something meaningful
Initially the image showed the first 20 lines of a file — which is always imports and require statements. Nobody wants to see import React from 'react' as their cover image.
Added findMeaningfulStartLine() — scans for the first class/function definition per language and starts there instead. Works for JS/TS, PHP, Python, Ruby, Java, Go, Rust, C#.
Tone profiles
One-time setup: paste a writing sample (old blog post, previous tweet, anything). Stored in ~/.commitpost/config.json. Every generated post runs through that sample as a style guide. Posts sound like you, not like ChatGPT.
The meta moment
I used commitpost to generate the LinkedIn post announcing commitpost. It worked.
Try it
# Install
npm install -g commitpost
# Set your API key (Anthropic)
commitpost config --set-key sk-ant-...
# Generate
commitpost generate
# With cover image
commitpost generate --include-image --image-style dark_code
GitHub: vsimke/commitpost
npm: commitpost
Post length is configurable (--length short/medium/long), there are 4 image styles, and 5 built-in tone profiles if you don't want to set up your own.
Open source, MIT. Would love feedback — especially from people using it on non-JS projects.
Top comments (0)