Overview
I wanted a security account on Instagram. Spending my evenings making posts for it was never part of the plan.
So the posts get made by a pipeline in n8n, self-hosted in Docker on my NAS. It only publishes through the official Instagram API, and it never publishes anything I haven't approved.
The week at a glance
monday 12:00 write this week's picks ──► judge them ──► keep the good ones
monday 14:00 each pick ──► telegram, with approve / reject
on approve render the images ──► store them ──► send them to me
tue thu sat scheduler ──► Instagram APIUp to six picks a week. Posts I approved that haven't gone out yet count against that number. The queue never runs away from me.
Writing the picks
The picks are text only at this stage. Images come later, and only for posts that survive.
[schedule]
│
▼
approved but not yet posted? ──► picks = 6 − that number
│
▼
┌─ generator: tip ───────┐
├─ generator: carousel ──┼──► Claude writes ──► format check ──► first text check
└─ generator: news ──────┘
│
▼
QA audit: 14 questions per pick ──► passes ──► picked
└► fails ──► logged, never sentClaude writes from a content guide that lives in my second brain. The guide holds my voice and every note I've left on past drafts. Each rejection makes the next batch a little better.
News needs two sources
The news generator reads eight security outlets and two official sources: CISA's list of actively exploited vulnerabilities and the breach list from Have I Been Pwned.
8 outlets (rss) + CISA KEV + HIBP
│
▼
headlines from the last 4 days
│
▼
pair headlines that share rare words ............ code
│
▼
"are these the same story?" ..................... Jev
│
▼
keep stories with 2+ outlets,
or 1 outlet + an official record ............... code
│
▼
score each story, take the best ................ Jev
│
▼
fetch the articles ──► Claude writes from those, and only thoseThe two-source rule lives in code. A model can rank stories, but it doesn't get to decide what counts as confirmed.
The judge
The judging is done by Jev, a "System One" decision model from TypeSafe AI. It never writes a word. You give it a piece of text and typed questions, and it answers with probabilities. For a quality gate that's exactly right, and it costs a fraction of a cent per post.
"hook": {
"type": "score",
"instructions": "How likely is the first slide plus the first caption line to make a security-curious person stop scrolling?",
"criteria": ["would scroll past", "mildly interesting", "likely to stop", "very likely to stop"]
}Every answer turns into one line of a readable audit. This is the audit of the first news pick that went out, a critical flaw in self-hosted Jira:
PICKED #1 · QA 0.81
✓ takeaway: very concrete (2.99/3)
✓ hook: very likely to stop (2.79/3)
✓ save/share: likely (2.16/3)
~ voice: mostly on-brand (1.59/3)
✓ beginner gets it: 0.85
~ pros respect it: 0.66
~ accuracy risk: 0.47
✓ repeat of a recent post: 0.29
pillar: news (1)Every candidate stays in a log for two weeks, with Jev's scores next to my verdict. That's the real test. If Jev keeps loving posts I reject, the weights change.
After I tap approve
telegram ✅ ──► IG Approval: handle ──► approved
│
IG Render approved, every 5 minutes
│
renderer (python) ──► image storage ──► album to my telegram
│
IG Scheduler: tue / thu / sat, evening window
│
IG Publisher ──► Instagram APIThe renderer is mine: Pillow and Pygments, with the site's fonts and colours. Templates are code. Every slide comes out consistent, and there's no second approval for the images. I just get to see them.
Security model
- Secrets live in n8n's credential store and nowhere else. Never in workflow files, never in chat.
- The Telegram buttons need one webhook path reachable from the internet. Every request on it has to carry a secret header and come from my Telegram account.
- Scraped news is treated as data. A headline that says "ignore your instructions" gets judged like any other headline.
- The posting pace and the human approval are deliberate. A brand-new account that suddenly posts like a content farm is how you get flagged.
What went wrong
The first live run of the scheduler failed. One n8n node hands on the row it just updated instead of the data it received. The publisher got a database row where it expected a post. Nothing reached Instagram, and the fix was one extra node.
Then the judge got paranoid about repeats. It turned down a post about email security for repeating one about password managers. Both were "about account security", and that was enough for it. The fix was telling it what does not count as a repeat. Vague questions get vague answers, even from a model that's supposed to be calibrated.
What's next
Turning my HackTheBox and home-lab notes into posts. The pipeline already watches for finished notes; the drafting step is the missing piece. Reels come after that.