Automating @readbytebrief: Architecting an Autonomous Multi-Agent Tech News Publisher
Most social media tech news curators follow a tedious, manual workflow: scouring Hacker News, drafting captions, launching design software (like Figma or Canva) to copy-paste headlines, exporting slides, and manually uploading them to Instagram. It is a slow, error-prone cycle that is difficult to maintain daily.
To automate this completely, I designed and built the architecture behind @readbytebrief—a fully autonomous multi-agent pipeline. Every day, the system fetches raw news from hundreds of tech sources, filters out duplicate coverage, identifies high-signal topics, generates professional editorial layouts, snapshots them at ultra-high resolution, and publishes multi-slide carousels to Instagram via the Meta Graph API. All with zero human intervention.
In this post, I will break down the modular multi-agent system, the token-efficient AI curation pattern, and the headless browser rendering tricks used to achieve professional editorial aesthetic.
1. The Multi-Agent Pipeline Architecture
Rather than building a single monolithic script, the system is decoupled into four specialized, autonomous agents that hand off structured JSON payloads to one another. This separation of concerns makes debugging, local visual testing, and modifying styling parameters extremely straightforward.
Importantly, the pipeline is not restricted to Instagram. Because the writer agent curates and structures tech news in a platform-agnostic format, the same pipeline aggregates and generates multi-tweet threads for Twitter/X and formatted markdown summaries in parallel. The entire system is built to be extensible—allowing us to syndicate the daily briefing to LinkedIn, Threads, or any other social platform by simply adding a new publisher agent wrapper.
2. High-Signal News Aggregation & Filtering
The newsAgent acts as the entry point, monitoring over 490+ tech topic categories across official AI labs (OpenAI, Google AI, Hugging Face), major engineering platforms (GitHub, Cloudflare, AWS), tech aggregators (Hacker News, trending subreddits), and developer ecosystems. To ensure only top-tier content progresses, articles are put through a sequential FilterPipeline:
- History Filter: Cross-references titles against a local JSON DB (
history_db.json) to skip coverage recently published in the last 72 hours. - Age Filter: Discards articles older than 24 hours to preserve freshness.
- Deduplication & Near-Duplicate Filter: Eliminates duplicate stories and semantically similar articles using string distances and key-term overlaps.
- Promotional Filter: Detects and discards marketing pitches, product launches, or commercial press releases.
- Relevance & Trust Ranking: Scores remaining articles using factors like source trust, Hacker News score, and general developer relevance.
The pipeline spits out the Top 30 ranked & verified articles to pass to the next stage.
3. Token-Efficient AI Curation
Feeding the full scraped HTML or body text of 30 articles directly into an LLM to select the best stories is highly inefficient and cost-prohibitive. It consumes massive input tokens and slows down execution.
To optimize this, the socialMediaWriter implements a two-phase curation pattern:
Phase 1: Title-Only Curation (Lightweight Prompt)
Send only titles, descriptions, and IDs of the 30 articles to the LLM (DeepSeek v4 Flash). The LLM returns a structured JSON list of the top 4 article IDs best suited for Instagram.
Phase 2: Targeted Scraping & Generation (Rich Context)
Only scrape the full webpage body content of those 4 selected articles. The scraped content is then sent to the LLM to generate the slide headline, body bullets, and final caption.
This optimization results in a ~85% decrease in LLM API costs, while still supplying the LLM with deep context for the final copywriting process.
4. Headless Visual Rendering and Crisp Image Export
Instagram has strict visual expectations: standard portrait carousel posts must be exactly 1080x1350 pixels (4:5 aspect ratio). Generating images dynamically using backend canvas libraries or server-side image toolkits can be tedious to code and painful to style responsively.
Instead, I designed the socialMediaPostAgent to render slides in HTML/CSS. This allows us to use modern layout tools like CSS Grid, Flexbox, custom typography (Instrument Serif and JetBrains Mono), and premium editorial styling tokens. We completely banned standard "AI blue/purple gradients" in favor of a warm obsidian background (#0d0d0f), paper white text (#f4f3ef), and amber highlights (#f59e0b).
To transform the HTML slides into high-resolution PNGs, we run a headless instance of Puppeteer. But capturing a typical 360x450px CSS element results in blurry, pixelated images. The solution? Setting a viewport scale factor of 3:
// Setting deviceScaleFactor to 3 scales up the output 3x
// 360px * 3 = 1080px width, 450px * 3 = 1350px height
await page.setViewport({
width: 1920,
height: 1080,
deviceScaleFactor: 3
});
// Capture screenshots directly on specific DOM elements
for (let i = 0; i < slides.length; i++) {
await slides[i].screenshot({
path: `output_images/slide_${i + 1}.png`,
type: "png"
});
}
This generates razor-sharp, native 1080x1350px PNG files that look extremely premium on mobile screens, meeting WCAG AAA contrast compliance.
5. Mathematical Near-Duplicate Filtration (Zero-Cost Vector Similarity)
Instead of importing heavy machine learning models or invoking external, paid embedding APIs to deduplicate stories, I engineered a lightweight, local Term-Frequency (TF) vectorizer in TypeScript. It strips punctuation, tokenizes text, filters out short stopwords, and builds a sparse term count map for each article. The similarity between two articles is then evaluated using sparse cosine similarity:
export const cosineSimilarity = (
vecA: Map<string, number>,
vecB: Map<string, number>
): number => {
let dotProduct = 0, normA = 0, normB = 0;
for (const [key, val] of vecA.entries()) {
normA += val * val;
if (vecB.has(key)) dotProduct += val * vecB.get(key)!;
}
for (const val of vecB.values()) normB += val * val;
if (normA === 0 || normB === 0) return 0;
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
};
By calculating this mathematical similarity metric locally, we prevent publishing near-identical stories across different feeds (e.g., Hacker News vs. Vercel Blog) in under 5 milliseconds per article, at zero API cost.
6. Developer Experience: Custom Hot-Reload Dev Server (Express + SSE)
To inspect the visual layouts and iterate on styles without having to run the entire pipeline or snapshot engine, I built a custom live-reload preview server (watch-server.ts) using Express and Server-Sent Events (SSE).
The server watches social_media_output.json for file system modifications using Node's watchFile. When a change is detected, it broadcasts a reload event to all connected browser tabs via SSE:
// SSE endpoint - browsers subscribe to listen to file changes
app.get("/events", (req, res) => {
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Connection", "keep-alive");
res.flushHeaders();
const client = { res };
clients.push(client);
req.on("close", () => {
const idx = clients.indexOf(client);
if (idx !== -1) clients.splice(idx, 1);
});
});
This custom DX setup provides real-time hot-reloading in the browser as the writer agent generates posts, ensuring perfect visual styling layout checks.
7. Continuous Delivery & Meta API Publishing
Once the slides are snapshot, the socialMediaPublisher manages the final delivery pipeline:
- Cloudinary CDN Upload: Uploads the local PNG assets to Cloudinary to generate publicly accessible HTTPS URLs. The Meta Graph API requires public image endpoints to download media.
- Carousel Creation: Hits the Meta Graph API (v19.0), issuing POST requests to create container IDs for each individual image slide (using the Cloudinary URLs).
- Container Stitching: Groups these individual item containers into a single parent carousel container.
- Final Publish: Issues the final publish command to publish the carousel along with the generated caption and hashtags to the target Instagram page.
The entire publisher is wrapped in a background queue worker that monitors daily engagement slots (e.g., 09:00, 13:00, 18:00, 21:00) to post when target audiences are most active.
Key Engineering Takeaways
- Decoupling over Monoliths: Separating fetching, curating, rendering, and publishing makes the code highly modular. If Instagram's API changes, only the publisher agent needs to be modified.
- Platform-Agnostic Design: Separating curation and rendering from final publishing allows the agent to scale across different media channels (such as Instagram, Twitter/X, and LinkedIn) from the same core datasource.
- Cost-Conscious Agent Workflows: Multi-step LLM execution (title filter → full content scraping → caption generation) is essential to scale agentic pipelines affordably.
- HTML as a Canvas: Using Puppeteer to snap HTML/CSS components with custom scale factors is a superpower for programmatic graphic design. It beats canvas manipulation by a mile.
By automating @readbytebrief, I turned a daily chore into an efficient, robust background utility that runs on a cron, showcasing how AI agents can operate complete digital assets with minimal overhead.
Thanks for reading.