●FORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtask●LIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its own●MCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MS●PLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callback●SONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15●IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as October●FORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtask●LIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its own●MCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MS●PLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callback●SONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15●IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as October
Notes from Seven Months of Running a Four-Site Auto-Publishing Pipeline with Claude Code and GitHub Actions
Lessons from running Claude Code scheduled tasks to auto-publish 16 articles a day across four Lab sites, including the Helpful Content System index collapse that forced a redesign of the quality gate, with the full Python gate code, token management, and rollback procedure.
Seven months ago, the indexed pages on Claude Lab dropped from 3,500 to 95 in a single week. The cause was unsurprising in hindsight: I had been letting Claude Code write articles on a daily schedule, and Google's Helpful Content System eventually flagged the output as "templated mass-generated thin content." A common story for anyone running an AI-driven blog at scale.
I am Masaki Hirokawa. I have been building iOS and Android apps as a solo developer since 2014 — roughly 50 million cumulative downloads — and currently run four Lab sites (Claude/Gemini/Antigravity/Rork) and two blog sites (Lacrima/Mystery) by myself, all on a Claude Code scheduled pipeline that publishes 16 articles a day. After the index collapse, I rebuilt the quality gate in Python and the pipeline has not crashed the same way since.
These notes cover the quality-gate design that survives 480 posts a month while you sleep, plus the operational habits around GitHub Actions, PAT rotation, and disk management. It is aimed at solo developers running multiple AI-assisted sites in parallel who have been bitten by the same quality-versus-quantity trap.
Why a Quality Gate Had to Be Bolted On
For the first few months, the setup was naive: a scheduled task per site that said "generate four articles per day and push." Topic selection, MDX writing, and git push all happened inside one Claude Code invocation. I assumed Claude was smart enough that machine-readable quality checks would be redundant.
After three months I opened Google Search Console and froze. Claude Lab's indexed pages had collapsed from 3,500 to 95. Monthly clicks went from 2,500 to 200 and impressions from 160K to 48K. There was no manual penalty notice, so this was algorithmic — Helpful Content System, almost certainly.
Re-reading the articles, the cause was visible: templated phrases like "in this article we will discuss," "how did you like it," and "the definitive guide" had crept in everywhere. Each article was fine on its own, but stacked over three months they made the entire site read like an AI template farm. From Google's algorithmic point of view, the same impression.
The lesson is the load-bearing premise of everything that follows. A loop where Claude writes, Claude judges, and Claude pushes — with no human in the middle — drifts toward template degradation. You have to insert one more inescapable, mechanical gate, or it eventually collapses.
Architecture — Four Sites, Four Posts Each, Run While You Sleep
Three points matter. (1) Claude Code does not only write — it also discards.(2) The quality gate lives in a separate Python process (article_gate.py) outside Claude's context, so judgment is not done by the same model that wrote the text. (3) The post-push validation in generate-content.mjs runs again in CI, giving you two independent sieves.
The bias problem is the reason. If you ask Claude to evaluate Claude's own output, the evaluation is generous. A dumb regex script that just counts pattern matches has none of that empathy, and Claude has to discard articles it personally liked when they trip a rule. That inescapability is what holds the pipeline together post-collapse.
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦A full picture of running a four-site, four-articles-per-day auto-publishing pipeline solo with Claude Code and GitHub Actions — including the role design that survives 480 posts per month without breaking.
✦The complete Python quality-gate code, derived from a real Helpful Content System incident where one site's indexed pages collapsed from 3,500 to 95 in a week, with each rule mapped to the failure mode it prevents.
✦Operations patterns for unattended overnight runs: GitHub PAT rotation, automatic disk reclamation, and autonomous error recovery — the things that actually let you sleep while the pipeline pushes.
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
The Heart of article_gate.py — Six Practical-Value Signals
The core rule for premium articles is the "practical signals" check. The first version used a hard floor — "premium articles must be at least 6,000 characters" — which turned out to be exactly the wrong axis. Short dense implementation guides were flagged as violations, while long template-padded articles passed.
Three months in, the lesson was clear: Helpful Content System dislikes not length but "templated AI explanation tone." I swapped the length floor for a six-signal rubric. Premium articles must hit at least three of these.
# excerpt from article_gate.pypractical_signals = []# (1) substantial code blocks (5+ lines)code_blocks = re.findall(r"```[\w-]*\n(.*?)```", body, re.DOTALL)if any(c.count("\n") >= 5 for c in code_blocks): practical_signals.append("code")# (2) concrete metrics (¥1,000 / 30% / 2.5x ...)money_patterns = [ r"[¥¥$]\s*[\d,]+", r"\d+(?:\.\d+)?\s*[%%]", r"\d+(?:\.\d+)?\s*[xX]",]if any(re.search(p, body) for p in money_patterns): practical_signals.append("metrics")# (3) structured procedure (numbered list >=3 or H3 >=3)numbered_steps = len(re.findall(r"^\s*\d+\.\s+", body, re.MULTILINE))h3_count = len(re.findall(r"^###\s+", body, re.MULTILINE))if numbered_steps >= 3 or h3_count >= 3: practical_signals.append("structure")# (4) operational gotchasinsight_patterns = [ r"(?:error|stuck|gotcha|pitfall|trap)", r"(?:workaround|resolve|fix)", r"(?:production|deploy|prod environment)",]if sum(1 for p in insight_patterns if re.search(p, body, re.IGNORECASE)) >= 2: practical_signals.append("insights")# (5) concrete recommendationsrecommendation_patterns = [ r"recommend(?:ed|s|ation)?", r"(?:I prefer|in my case|in practice|personally)",]if sum(1 for p in recommendation_patterns if re.search(p, body)) >= 2: practical_signals.append("recommendations")# (6) domain-specific metricsdomain_metrics = [r"eCPM", r"LTV", r"DAU", r"AdMob", r"RevenueCat", r"Stripe"]if any(re.search(p, body, re.IGNORECASE) for p in domain_metrics): practical_signals.append("domain")if len(practical_signals) < 3: violations.append(f"premium lacks practical value: {practical_signals}")
Since switching to this rubric, Claude stopped padding paragraphs to hit length targets. Instead it adds one code example, one metric, or one gotcha — whichever raises density. The signal is concrete enough that template expansion no longer has anywhere to hide.
Machine Detection of Template Phrases
In parallel with the practical-value rubric, the gate aggressively pattern-matches template phrases that look harmless in isolation but stack into "AI template farm" at site scale.
# Intro templates (caught within first 800 chars)INTRO_TEMPLATES = [ "this article will discuss", "this article covers", "let us dive into", "in this guide", "we will explore",]# Title templatesTITLE_TEMPLATE = [ "Complete Guide", "Comprehensive Guide", "Ultimate Guide", "Everything You Need to Know", "The Definitive Guide",]# Closing templatesCLOSING_TEMPLATE = [ "how did you like", "in conclusion, we discussed", "be sure to give it a try",]
What works best is the template H2 detection — flagging when the article structure is just "## Introduction / ## Background / ## Conclusion." That structure alone is a strong tell for AI generation. Mixing it with two or more of the title or intro patterns produces a near-perfect classifier for low-effort generation.
The other catch worth mentioning is AI tone-marker overuse. Phrases like "you can easily," "it is important to note," and "as we can see" are fine once or twice but trigger a violation at three or more occurrences in a single article. Three occurrences of any one phrase is the threshold where the writing starts to read mechanically.
Token Management — Carrying Four GitHub PATs Safely
Each site needs its own GitHub PAT. Embedding them directly in the scheduled task prompt leaks them into task exports and logs, so I keep them in a single file in the workspace and grep for them inline.
Two principles. (1) Never put a PAT in the scheduled task prompt itself — put it in a file and pull it in at run time. (2) Reuse /tmp/repos/{site}/ across sessions. Cowork keeps /tmp between sessions, and git pull --rebase is far cheaper than re-cloning each run.
I rotate PATs every 90 days. The whole rotation flow is "update the text file, git commit." The task prompts never have to be touched, which keeps operational cost trivial.
Auto-Reclaim on Low Disk
/tmp is shared with other Cowork tasks, so six repos plus npm caches eventually starve the disk. The reclaim logic I built for Claude Lab is reused across all four sites.
FREE_MB=$(df /tmp --output=avail -m 2>/dev/null | tail -1 | tr -d ' ')# Below 500 MB, drop other sites' reposif [ "${FREE_MB:-0}" -lt 500 ]; then echo "Low disk: $FREE_MB MB. Cleaning up other sites..." for OTHER in /tmp/repos/*; do if [ "$OTHER" != "$WORK" ]; then rm -rf "$OTHER" 2>/dev/null fi donefi# Still tight? Drop npm cacheFREE_MB=$(df /tmp --output=avail -m 2>/dev/null | tail -1 | tr -d ' ')if [ "${FREE_MB:-0}" -lt 500 ]; then npm cache clean --force 2>/dev/nullfi
Wiping sibling repos sounds aggressive but is safe — git pull --rebase restores them on the next run. The cardinal rule is the current $WORK is the only thing we cannot touch. Making that boundary explicit is what keeps autonomous execution from breaking itself.
Count Parity — The Last Wall Against JA/EN 404s
All four Lab sites are bilingual via next-intl v4. A missing English version causes a 404 on language switch. The CI consistency check catches it eventually, but Claude Code verifies parity in-task before push.
If parity fails, Claude Code is instructed to regenerate the missing language, and to skip the whole run if it still cannot match. Allowing Claude to skip a day is what keeps the system honest. Pressuring a fixed quota of four posts per day is the path back to template padding and another Helpful Content collapse.
Internal Link Existence — Catching Phantom References
MDX bodies sometimes contain text links pointing at articles that no longer exist (or never did — Claude occasionally invents plausible-looking slugs). The prebuild script in CI checks every link against the article index.
// generate-content.mjs (runs in Cloudflare Pages CI)const internalLinks = body.matchAll( /\[([^\]]+)\]\(\/articles\/([^/]+)\/([^)#]+)\)/g);for (const [, text, category, slug] of internalLinks) { if (!articleIndex.has(`${category}/${slug}`)) { console.warn(`broken link in ${file}: /articles/${category}/${slug}`); body = body.replace(/* replace with plain text */); }}
Broken links are quietly downgraded to plain text. The build is not failed — failing the build at this layer means the whole site stops deploying overnight, which is worse than a few broken internal links being silently neutered.
Autonomous Error Recovery
Claude Code is instructed to recover from errors without asking the user. The explicit recovery list lives in SKILL.md:
- git push rejected → git pull --rebase, retry push
- repo corrupted → rm -rf /tmp/repos/{site}, re-clone
- article_gate.py violations → discard, regenerate (max 3x)
- npm install failed → ignore (Cloudflare CI handles prebuild)
- count mismatch → generate the missing side; skip the run if still off
The "do not ask the user" line is the load-bearing one. Without it Claude Code politely calls AskUserQuestion and the overnight run stalls. Codifying the autonomous-execution policy per task, together with an explicit ban on tools that show permission dialogs (request_cowork_directory, computer-use tools), is what makes unattended operation actually unattended.
Why 480 Posts a Month Does Not Implode — The Second Gate
Articles that pass the in-task Claude Code gate hit a second consistency check in generate-content.mjs during Cloudflare Pages CI:
premium / level frontmatter mismatch between JA and EN → auto-corrected to JA values
API key real-format leaks in code examples (AIzaSy, ghp_, sk_live_) → build fails
Markdown table without remarkGfm support → warning
Missing OGP image reference → fallback to default
Internal link existence
If this fails, Cloudflare aborts the deploy. The failure email arrives via GitHub, so a bad article either becomes a deploy you can address in the morning or never goes live. The two-stage gate is what eliminated overnight accidents of "weird article was indexed before I noticed."
Rollback Procedure — For When Both Gates Are Not Enough
A few times even the two-stage gate has not caught a real problem. The hardest case is "the article passes both gates, but its presence dilutes the surrounding articles' overall site quality assessment" (typical example: a templated comparison article gets added, and Google now groups it with adjacent templated comparison articles into a low-quality cluster). That is genuinely hard to predict pre-push.
So rollback is standardized on Git.
# list articles added in the last 24 hourscd /tmp/repos/claudelab.netgit log --since="24 hours ago" --name-only --pretty=format: \ | grep "content/articles/" | sort -u# quarantine then deletemkdir -p "_documents/_quality_audit/quarantine/$(date +%Y%m%d)"for f in $(git log --since="24 hours ago" --name-only --pretty=format: \ | grep "content/articles/" | sort -u); do cp "$f" "_documents/_quality_audit/quarantine/$(date +%Y%m%d)/" git rm "$f"donegit commit -m "Quarantine: pull last 24h"git push origin main
Always quarantine before git rm. Once the article is recognized as actually good later, you can restore it. After the Claude Lab Helpful Content collapse, this same procedure was used to quarantine 74 articles in a week. On Gemini Lab a parallel sweep quarantined 183 articles. Both sites posted +0.5 to +0.9 average position improvement within two weeks, which numerically confirmed that most quarantined articles were low quality to begin with.
Costs and Outcomes After Seven Months
The quantitative picture:
Auto-publishing: 480 articles/month (4 sites x 4/day x 30 days)
Human time: ~30 minutes/week (PAT rotation, log review, rollback judgment)
Infrastructure cost: Cloudflare Pages free tier + Claude API (~$15/month at Sonnet 4.6 usage)
Recovery cost (Helpful Content cleanup): ~8 hours of manual review and quarantine
Before the collapse I assumed Claude-as-author would scale linearly with site count. Including the quality gate plus operational overhead, the real scaling factor is site count x judgment difficulty, which is super-linear. Four sites feels like the practical solo ceiling. Going beyond that requires another quality-judgment layer (e.g., a separate model scoring articles post-generation), which is what comes next.
What I Plan to Add Next
Three open items remain.
First, semantic duplicate detection. Surface-level template detection is solid, but the gate cannot tell when a new article duplicates 70% of an existing one's content. Embedding-based similarity scoring is in design.
Second, post-publish evaluation using GSC data. A weekly job that finds articles still at zero clicks after 30 days and pushes them to a quarantine queue would close the generate-evaluate-quarantine loop into a self-cleaning system.
Third, a premium-upgrade pipeline for free articles. Free articles with strong engagement (long dwell time, deep scroll) get re-read by Claude, augmented with first-person experience and concrete metrics, and re-published as premium. Starting that experiment in June 2026.
If you are also running multiple AI-assisted sites solo, I hope these notes help. I am still in the middle of learning this myself, and feedback or improvements via dolice.design are welcome.
Share
Thank You for Reading
Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.