惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Cisco Blogs
NISL@THU
NISL@THU
G
GRAHAM CLULEY
T
Threatpost
I
Intezer
D
Darknet – Hacking Tools, Hacker News & Cyber Security
P
Proofpoint News Feed
L
Lohrmann on Cybersecurity
Cisco Talos Blog
Cisco Talos Blog
P
Privacy & Cybersecurity Law Blog
Security Latest
Security Latest
P
Palo Alto Networks Blog
L
LINUX DO - 热门话题
Cyberwarzone
Cyberwarzone
AI
AI
Help Net Security
Help Net Security
Forbes - Security
Forbes - Security
T
The Exploit Database - CXSecurity.com
月光博客
月光博客
The GitHub Blog
The GitHub Blog
aimingoo的专栏
aimingoo的专栏
C
CERT Recently Published Vulnerability Notes
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
N
News and Events Feed by Topic
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Scott Helme
Scott Helme
A
About on SuperTechFans
N
Netflix TechBlog - Medium
TaoSecurity Blog
TaoSecurity Blog
V
V2EX
MongoDB | Blog
MongoDB | Blog
AWS News Blog
AWS News Blog
Google DeepMind News
Google DeepMind News
Google Online Security Blog
Google Online Security Blog
O
OpenAI News
Y
Y Combinator Blog
S
Securelist
GbyAI
GbyAI
D
Docker
SecWiki News
SecWiki News
The Hacker News
The Hacker News
有赞技术团队
有赞技术团队
T
Tenable Blog
WordPress大学
WordPress大学
S
SegmentFault 最新的问题
P
Privacy International News Feed
S
Security Affairs
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Hacker News - Newest:
Hacker News - Newest: "LLM"
H
Hackread – Cybersecurity News, Data Breaches, AI and More

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Building an autonomous multi-agent SEO system with Claude + GitHub Actions ("cheap" and quick)
Jesús Bosch · 2026-05-10 · via DEV Community

I needed SEO content for a Chrome extension I built. The arithmetic of doing it myself was discouraging: six to eight hours per post if I wanted it to be good, plus another two for translations into Catalan and Spanish (I know, I know). I was not going to write four posts a week. I was not going to write one post a week reliably either.

I knew AI Agents could come to the rescue, but those usually require an expensive token economy... and I'm on a budget, so I had to find creative ways to get the work done without breaking the bank.

So I came up with a system that does it. Seven Claude-backed agents orchestrated through five GitHub Actions workflows, with the human only stepping in to merge a PR (or to ignore it). It runs at around $1.50 per article in three languages, including custom SVG diagrams and Open Graph cards. At my publishing cadence (one post a week), the API spend is roughly $7 a month.

Below is what is actually inside it, with the design choices that made it cheap.

The five flows

Each flow is a workflow file in the consumer-site repo. The agent code itself lives in a separate Python package; each workflow installs it via pip install git+...@main and calls a CLI entry point. That separation means I iterate prompts without touching workflows, and bumping the agent version is a one-line change in the workflow file.

  • Flow A (weekly content): cron-triggered. Strategist picks the next pending topic from a hand-curated backlog, Writer produces an MDX post, Editor accepts or rejects with structured feedback, retry loop up to three times. Image Generator produces a thumbnail, an OG image, and one to three inline SVG diagrams. Build verification, PR opened with a content-review label, I get an email.
  • Flow B (PR feedback): triggered when I comment @seo-agent ... on the open PR. Writer regenerates the MDX with my instruction. No Editor here, because I am the reviewer at this point.
  • Flow C (technical SEO audit): issue-triggered. Technical Analyst reads a Search Console warning I paste in, decides if it is a false positive, opens a fix PR only if not.
  • Flow D (monthly topic research): cron-triggered. Topic Generator uses Anthropic's server-side web_search to read Reddit, indie-developer forums, and competitor blogs, then proposes five to six topics aligned with my reader profile. The PR auto-merges and the backlog refills.
  • Flow E (post-merge translation): triggered when I merge Flow A's PR. Translator produces Catalan and Spanish versions, Image Generator translates body-diagram SVG labels per locale, the translation PR opens and auto-merges in four seconds.

Only Flow A and Flow C produce PRs that need my review. Flow D and Flow E auto-merge because the human gate is upstream (I curate the topic in D, I approved the EN draft in A before E fired).

Per-agent model selection (where the savings come from)

Most multi-agent setups I have read about use one model for everything. That is the wrong abstraction. Each agent has a different job, and each job has a different cost-quality sweet spot.

STRATEGIST_MODEL = "claude-haiku-4-5"        # JSON in, JSON out, cheap
WRITER_MODEL = "claude-opus-4-7"             # long-form prose, voice matters
EDITOR_LLM_MODEL = "claude-haiku-4-5"        # one binary judgment
TECHNICAL_ANALYST_MODEL = "claude-sonnet-4-6"
TOPIC_GENERATOR_MODEL = "claude-sonnet-4-6"  # needs web_search (no Haiku support)
TRANSLATOR_MODEL = "claude-sonnet-4-6"       # structure-preserving translation
IMAGE_GENERATOR_MODEL = "claude-sonnet-4-6"  # SVG with strict layout rules

Enter fullscreen mode Exit fullscreen mode

Real per-post breakdown from the runs log:

Agent Model Cost
Strategist Haiku 4.5 $0.01
Writer (1 iteration) Opus 4.7 $0.60-0.75
Editor (1 LLM call) Haiku 4.5 $0.01
Image Generator (thumbnail + OG + 1 diagram) Sonnet 4.6 $0.10
Flow A subtotal ~$0.76
Translator x 2 locales Sonnet 4.6 $0.20
OG localized x 2 Sonnet 4.6 $0.04
Diagram translate x 2 locales Sonnet 4.6 $0.14
Flow E subtotal ~$0.38
Topic Generator (monthly, amortized over 4 posts) Sonnet 4.6 + web_search $0.22
Total per post (three languages, all assets) ~$1.36

Writer cost is 60-70% of the total. I tried Sonnet 4.6 first; the prose was technically fine but read formulaic, with the kind of "X takes care of itself" tics that betray automated generation. Opus produces a noticeably more idiomatic editorial voice. At the volume I publish, the absolute monthly delta is around $5. Worth it.

Prompt caching across the Writer-Editor loop

The Writer can need two or three iterations to pass the Editor. The brief, the voice guide, the product doc, and the component schemas are identical across iterations. Naively re-sending the whole prompt every iteration means paying full input rate three times.

Anthropic's prompt caching solves this. The Writer call splits its prompt into a stable prefix (cached) and a dynamic suffix (the editor feedback and previous draft):

result = client.complete(
    system=WRITER_SYSTEM_PROMPT,
    user=_build_dynamic_suffix(inputs),
    cached_user_prefix=_build_cached_prefix(inputs),
    max_tokens=8192,
    model=WRITER_MODEL,
)

Enter fullscreen mode Exit fullscreen mode

The cached prefix is sent once and reused for about five minutes. Iterations 2 and 3 pay roughly 10% of the full input rate on those tokens. On a real post that translates to $0.10-0.15 saved per retry, and Opus retries are not cheap.

The Editor: regex first, Claude only when needed

The Editor runs around 21 deterministic checks before invoking any LLM:

  • Frontmatter: date is a quoted ISO string, title under 60 chars, excerpt under 160 chars, slug is strict kebab-case.
  • Structure: TldrBlock immediately after intro, anchor links resolve to H2 ids, components match the brief, visual variety (no two consecutive prose-only sections), pull-quote count between one and three, section word counts within tolerance.
  • Body content rules: no meta-instruction phrases ("here is how", "in this post we"), no SDR-style EmailMockup copy ("discovery call", "sales sequence"), mandatory Mail2Follow CTA block at the end, product link present at least once.
  • Voice and brand: banned-phrase list clean (no "leverage", no em dashes, etc.), no founder names in EmailMockup signatures, no cross-promotion of other products.

These cost nothing. They run on the Writer's output before any Claude call, and they catch about 80% of the failure modes the Writer produces.

After the deterministic checks, one LLM call to Haiku 4.5 (around $0.01) handles what regex cannot judge: fabricated numeric claims and fabricated personal anecdotes. The check returns structured JSON the pipeline injects into the next Writer iteration as a specific instruction.

This regex-first design is why the Editor is essentially free per pass. Most multi-agent systems I have read about use an LLM critic for everything, which works, but it costs 30-50x more for the same job.

The retry loop with structured feedback

When the Editor rejects, the Writer is called again with the original brief, the previous draft, and a list of failed checks. Each FailedCheck carries a specific, actionable instruction:

FailedCheck(
    check="no_sensory_anecdotes",
    instruction=(
        "The body contains 'a reform contractor I know in Sant Cugat'. "
        "The agent cannot have first-hand sensory or biographical "
        "anecdotes. Rewrite as an archetypal scenario."
    ),
)

Enter fullscreen mode Exit fullscreen mode

The Writer reads these in its prompt as a numbered list of items to fix. Up to three iterations. If the Editor still rejects after retry three, the workflow opens a GitHub issue with the failed drafts and exits non-zero. I see the issue in my inbox the next morning.

Anti-fabrication rules

Early in development the Writer was producing prose like "A reform contractor I know in Sant Cugat sent five quotes one Tuesday in March". Compelling reading. Also entirely invented. The Writer has no body, did not visit places, did not meet contractors. Pretending otherwise is an ethical line.

The current rule:

  • The Writer cannot use first-person sensory or biographical constructions ("I saw", "I drove past", "told me over coffee", "a [role] I know in [place]").
  • Replace with archetypes: "Consider a freelance architect who sends four proposals a month..."

Deterministic regex catches the obvious patterns; the LLM check catches subtler fabrications.

This is the rule that took the most calibration. The rules that caused the Writer to fabricate were the rules I had written months earlier ("first-person founder voice, use 'I' and 'my', reference real founder experience") to make the prose more vivid. The vividness came from invention. Removing the mandate produced posts that read more reserved but truthful.

Cultural translation, not literal

The Translator started by producing word-perfect Catalan and Spanish that no native speaker would actually write. "Just checking in" became "només volia saber com estàs" — a calque from English that comes out of Google Translate, never a Catalan inbox.

The fix was an idiom-substitution table embedded in the Translator prompt:

| English source        | Catalan         | Spanish         |
|---|---|---|
| just checking in      | com anem?       | qué tal?        |
| circling back         | et torno a      | vuelvo a        |
|                       | escriure        | escribirte      |
| touch base            | fer un toc      | ponernos en     |
|                       |                 | contacto        |
| outreach              | captació        | captación       |
| chase an invoice      | reclamar una    | reclamar una    |
|                       | factura         | factura         |

Enter fullscreen mode Exit fullscreen mode

Plus an explicit instruction: the model is authorized to deviate from the literal source when a literal translation would produce a calque. The constraint is faithfulness to the post's intent, not to the source's word order.

Body diagrams (SVG with text labels) get a separate translation pass: an Image Generator function reads the EN SVG and rewrites only the <text> content into the target locale, preserving every other byte (geometry, classes, fills, transforms). The Catalan post points at <localized-slug>-<section>.svg, the Spanish post at its own variant.

Three things that surprised me in production

MDX paragraph-wrapping breaks layout in ways HTML does not. The CTA pill at the bottom of every post is <a class="cta-pill"><span>Try Mail2Follow free</span><svg .../></a>. With the text on a separate line in the source, the MDX compiler wraps it in a <p> element, which is block-level, which breaks the inline-flex layout and pushes the chevron to its own line. Reference posts authored in raw .md were unaffected. Agent-authored .mdx posts hit it on every build until I switched the anchor contents to a single line and wrapped the label in a <span> as a second line of defence.

Slug paths with hyphens trip greedy regex. The body-diagram src is /blog-images/diagrams/<slug>-<section>.svg. Both slug and section are kebab-case strings; a single regex over both cannot determine the split (follow-up-quote-contractor-no-response-five-day-window could split anywhere there is a hyphen). The fix is to compile the regex per call against the actual source slug as a literal:

diagram_re = re.compile(
    rf"/blog-images/diagrams/{re.escape(source_slug)}-(?P<section>[a-z0-9-]+)\.svg"
)

Enter fullscreen mode Exit fullscreen mode

I caught this on the first real run with body-diagram translation enabled. The pipeline silently produced no localized diagrams because the regex captured the wrong split, the slug filter rejected every match, and the loop iterated zero times. The runs log showed zero diagram_translate entries; the symptom was the absence of expected work.

The cheapest failure to recover from is the one that opens a tracking issue. The pipeline catches AnthropicClientError around each agent call and opens a GitHub issue with the brief, the iteration index, and the error message. When Anthropic deprecated temperature on Opus 4.7, the workflow exited with a clean issue titled "[SEO Agent] Writer call failed for 'X'" instead of a stack trace buried in the CI log. Thirty lines of code; removed all the debugging time.

What I would change if I were starting over

The Editor's binary checklist grew organically from "fix this specific thing the Writer just produced" cycles. After 25 checks, the right structure is probably to group them by phase (frontmatter, structure, voice, brand) and run them in stages so the rejection message tells the Writer which class of issue to focus on first. Currently every retry tries to fix everything at once, which works but reads as a long list of unrelated complaints in the prompt.

The cost-tracking JSONL is fine for an aggregator command, but a small dashboard with weekly cost-per-post charts would have caught one optimization opportunity earlier (the editorial voice pivot dropped Editor LLM calls from two per pass to one; I noticed three weeks after I could have saved $0.005 per post).

I would also invest sooner in a "sample 10 posts and read them critically" cadence. Most of the prompt-iteration value came from reading actual output, not from designing prompts in the abstract.

The cost question, summarised

Writing 1500-2000 words of editorial content in three languages, with custom diagrams and OG cards, for around $1.50 per post. Including a real human review step (mine) and a four-second auto-merge for the translations. Monthly API spend at one post a week: about $7. Annually: around $85.

A freelance writer + translator + illustrator on the same scope is $400-1000 per post. The system is 0.2-0.4% of that cost, with the trade-off that I do the strategic work (topic curation, prompt iteration, taste review).

It is not magic. It is seven specialized prompts, regex-first quality gates, prompt caching, a retry loop with structured feedback, and a discipline of not pretending the agents have lived an experience. The architecture diagram up top is the system. Everything else was calibration.

What you can take from this

If you build an indie product that needs SEO content without a salaried content team, the architecture is replicable. The hard parts are not the agents themselves. They are:

  1. The editorial taste they are trained on, which lives in two markdown files (agent-context/founder-voice.md and agent-context/products.md) you will rewrite many times before the output stops sounding generic.
  2. The deterministic checks, which look trivial in isolation but compound. Every regex check that catches a specific failure mode is one fewer LLM call you pay for.
  3. The retry loop with structured feedback, because LLM critics that only say "this is wrong" without an actionable instruction force the next iteration to guess.

If you want to see what the system actually outputs, the Mail2Follow blog runs entirely on this pipeline. The product itself (Mail2Follow) is a Chrome extension that tracks sent emails, drafts tone-matched follow-ups inside Gmail, and respects sensitive domains via the Mozilla Public Suffix List. It is the indie tool I needed the SEO content for in the first place.

If you have built something similar with a different architecture, I would actually like to hear how you handled the editor-critic loop. Mine is binary; the alternatives I have considered (LLM-as-critic with continuous scores, multi-pass with separate stylistic and factual reviewers) all cost more without an obvious quality lift, but I have not run that comparison rigorously.