<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dystymis</title>
    <description>The latest articles on DEV Community by Dystymis (@dystymis).</description>
    <link>https://dev.to/dystymis</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4171742%2F533b6261-340f-42f8-883c-76c63e64a164.jpg</url>
      <title>DEV Community: Dystymis</title>
      <link>https://dev.to/dystymis</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dystymis"/>
    <language>en</language>
    <item>
      <title>380 Articles, 5 Sites, $0 Hosting: What an AI Agent Learned Building a Content Network</title>
      <dc:creator>Dystymis</dc:creator>
      <pubDate>Thu, 08 Oct 2026 16:29:58 +0000</pubDate>
      <link>https://dev.to/dystymis/380-articles-5-sites-0-hosting-what-an-ai-agent-learned-building-a-content-network-2bpd</link>
      <guid>https://dev.to/dystymis/380-articles-5-sites-0-hosting-what-an-ai-agent-learned-building-a-content-network-2bpd</guid>
      <description>&lt;h1&gt;
  
  
  380 Articles, 5 Sites, $0 Hosting: What an AI Agent Learned Building a Content Network
&lt;/h1&gt;

&lt;p&gt;Five Russian-language niche sites are live as subfolders of a single free GitHub Pages domain: home and cleaning tips, car maintenance, gardening, health, and an 18+ intimacy section. As of the deploy on 7 October 2026 they hold &lt;strong&gt;380 published articles — 76 per site — plus five hub pages&lt;/strong&gt;, all statically rendered, all covered by six sitemaps. The monthly hosting bill is $0. Roughly 90% of the work — writing, QA, deployment, index requests, RSS distribution, Telegram posting, directory outreach — is done by an AI agent I run locally. I review output and decide the rules the agent must not break.&lt;/p&gt;

&lt;p&gt;Two numbers set the rhythm of the whole operation: Google Search Console allows &lt;strong&gt;10 "request indexing" submits per day&lt;/strong&gt;, and Yandex Webmaster allows &lt;strong&gt;150 recrawl URLs per day&lt;/strong&gt;. Everything else — batch sizes, deploy cadence, outreach tempo — is scheduled around them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup: one domain, five niches, no hosting cost
&lt;/h2&gt;

&lt;p&gt;Each site lives at &lt;code&gt;dystymis.github.io/{site}/{slug}/&lt;/code&gt; — no &lt;code&gt;/articles/&lt;/code&gt; segment, no database, no CMS. Each has its own repository, and a &lt;code&gt;dist/&lt;/code&gt; folder is the single source of truth: a &lt;code&gt;deploy.ps1&lt;/code&gt; script robocopies &lt;code&gt;dist/&lt;/code&gt; into each repo and pushes. The hub repo holds the root page, &lt;code&gt;sitemap-hub.xml&lt;/code&gt;, &lt;code&gt;llms.txt&lt;/code&gt;, a &lt;code&gt;robots.txt&lt;/code&gt; with 23 AI-crawler groups, and the verification files Google and ad networks ask for.&lt;/p&gt;

&lt;p&gt;Per site you get an XML sitemap (78 URLs: hub, about page, 76 articles), an RSS feed with 20 items, JSON-LD for Article, Breadcrumb and FAQPage, 1200x630 OG images generated by a small PowerShell script, a manifest, &lt;code&gt;security.txt&lt;/code&gt;, &lt;code&gt;humans.txt&lt;/code&gt;, plus a Wikidata item and snapshots in Wayback and archive.today.&lt;/p&gt;

&lt;p&gt;Free hosting was a cost decision, not an SEO strategy — and it turns out to be the single most consequential property of the project. More on that below.&lt;/p&gt;

&lt;p&gt;You can see the network root at &lt;a href="https://dystymis.github.io/" rel="noopener noreferrer"&gt;https://dystymis.github.io/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pipeline: from keyword to deployed article
&lt;/h2&gt;

&lt;p&gt;Content moves in batches of 50 articles (10 per site). The flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Plan&lt;/strong&gt; — keywords are clustered into a JSON plan file per batch, with slug, title and date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Briefs&lt;/strong&gt; — one Markdown brief per site, generated from the plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two parallel agents&lt;/strong&gt; — agent A strips boilerplate and writes unique H3 sections, agent B handles the sensitive parts: 18+ gating on the intimacy site (56/56 files), YMYL disclaimers (56/56), descriptions within 143–160 characters, and two checked external citations per health batch (who.int, rospotrebnadzor.ru).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;QA&lt;/strong&gt; — a Python script validates frontmatter, dates (no future dates: Yandex RSS rejects them), titles, descriptions, JSON-LD and internal links. It prints &lt;code&gt;ALL OK&lt;/code&gt; or a fix list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build&lt;/strong&gt; — a Node script (&lt;code&gt;build.js&lt;/code&gt;) renders static HTML with &lt;code&gt;fitTitle()&lt;/code&gt; capping titles at 60 characters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy&lt;/strong&gt; — &lt;code&gt;deploy.ps1&lt;/code&gt; pushes five repos, then &lt;code&gt;ping-indexnow.ps1&lt;/code&gt; submits the batch. The last batch pushed &lt;strong&gt;346 URLs accepted by IndexNow&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Three batches in three days took the network from 280 to 330 to 380 articles. No queue, no CMS upgrades, no plugin conflicts — because there is no CMS.&lt;/p&gt;

&lt;p&gt;One example article the pipeline produced: &lt;a href="https://dystymis.github.io/soveti-doma/hranenie-hleba/" rel="noopener noreferrer"&gt;Срок хранения хлеба: условия, упаковка&lt;/a&gt; — a table-driven piece on bread storage life, with FAQ schema and internal links to neighbouring storage articles. Note the truncated title in the browser tab: that is &lt;code&gt;fitTitle()&lt;/code&gt; doing its job a bit too literally, one of the small defects still on the fix list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Indexing: what 10 requests per day actually feels like
&lt;/h2&gt;

&lt;p&gt;Google's quota is a hard wall. Ask for the 11th URL and you get a dialog saying the quota is exceeded until tomorrow. The agent's workaround details are the opposite of glamorous:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The "Request indexing" button is only clickable through JavaScript — an obfuscated class name, &lt;code&gt;textContent&lt;/code&gt; match, non-zero &lt;code&gt;getBoundingClientRect()&lt;/code&gt;, then &lt;code&gt;.click()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The search input needs a native value setter plus &lt;code&gt;input&lt;/code&gt;, &lt;code&gt;change&lt;/code&gt; and &lt;code&gt;keydown&lt;/code&gt; events, because Playwright's &lt;code&gt;.click()&lt;/code&gt; is intercepted by an overlay.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reload before every inspection.&lt;/strong&gt; The "Submitted" panel is session state; without a reload you get a false positive from a stale panel.&lt;/li&gt;
&lt;li&gt;Quota errors arrive as a &lt;code&gt;[role=dialog]&lt;/code&gt; element, not as body text — a regex over the page will miss them.&lt;/li&gt;
&lt;li&gt;MCP call timeouts mean one URL per invocation, so a full day of 10 requests is 10 separate orchestration steps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yandex is friendlier: 150 recrawl requests a day via a plain REST &lt;code&gt;POST /recrawl/queue&lt;/code&gt;, one URL per request, &lt;code&gt;202&lt;/code&gt; plus a task id. (The MCP helper for it 404s — we hit the API directly.)&lt;/p&gt;

&lt;p&gt;For everything beyond those 160 daily slots there is IndexNow, which accepted 346 URLs in a single push. Bulk goes to IndexNow and sitemaps; the scarce GSC quota is reserved for pages that matter most.&lt;/p&gt;

&lt;p&gt;Two honest failures here. First, the network root sat at &lt;code&gt;noindex, follow&lt;/code&gt; without a canonical tag for weeks, so the main page was missing from the index while everything below it was fine — fixed in two commits, and &lt;code&gt;site:dystymis.github.io&lt;/code&gt; was sitting at &lt;strong&gt;5 results&lt;/strong&gt; as the baseline. Second, a GitHub Pages build stuck in queue for 55 minutes; the fix was cancelling the workflow run and retriggering with an empty commit. Neither failure was in the content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Distribution that runs without me
&lt;/h2&gt;

&lt;p&gt;The five RSS feeds feed a Python script (&lt;code&gt;autopost.py&lt;/code&gt;) that reads &lt;code&gt;dist/*/feed.xml&lt;/code&gt;, dedupes by GUID against a &lt;code&gt;posted.json&lt;/code&gt; state file, formats a title plus description plus "read on site" link as HTML, sleeps 3 seconds between messages, and posts through the Telegram Bot API to &lt;code&gt;t.me/dystymis_tips&lt;/code&gt;. A Windows scheduled task (&lt;code&gt;schtasks /SC HOURLY /MO 4&lt;/code&gt;) runs a &lt;code&gt;.cmd&lt;/code&gt; wrapper every four hours — environment variables inside &lt;code&gt;/TR&lt;/code&gt; break the task parser, so the wrapper exists. The bot &lt;code&gt;@dystymis_tips_bot&lt;/code&gt; posts into a channel it could not even join: Telegram rejects bots as subscribers with &lt;code&gt;RPC 400 USER_BOT&lt;/code&gt;, so it was promoted to admin with post rights instead, found only through the web client whose admin picker does global search. Selected posts then go to Dzen.&lt;/p&gt;

&lt;p&gt;Everything in this section costs nothing: RSS, Bot API, Task Scheduler. The token file is UTF-8 with a BOM, which cost one confusing round of &lt;code&gt;401 Unauthorized&lt;/code&gt; before anyone thought to read it as &lt;code&gt;utf-8-sig&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did not work
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Teaser networks filter free hosting.&lt;/strong&gt; Buymedia answered with "blocked — free hosting". TeaserMedia and Kadam declined; Visitweb wants at least 50 visits a day before it looks at you. HilltopAds approved both ad zones, Adsterra and PopCash accepted the sites, Dao.AD and AdsKeeper are in moderation — but with traffic near zero, approval is paperwork, not revenue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Traffic is not there yet.&lt;/strong&gt; For the week of 26 September – 2 October: 77, 46, 34, 28 and 25 pageviews across the five sites, mostly my own visits. GSC reported &lt;strong&gt;0 impressions over 14 days&lt;/strong&gt;. 380 published articles is a supply number, not a demand number.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Outreach is a numbers game with a lot of dead ends.&lt;/strong&gt; One round, five agent tabs open in parallel in a single browser, &lt;strong&gt;275 submission attempts&lt;/strong&gt; logged to JSONL journals:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Outcome&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PUBLISHED&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PENDING_MODERATION&lt;/td&gt;
&lt;td&gt;51&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SUBMITTED (unconfirmed)&lt;/td&gt;
&lt;td&gt;48&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PAID-only&lt;/td&gt;
&lt;td&gt;31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Registration required (skipped)&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dead pages / broken forms&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adult content rejected (18+ site)&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CAPTCHA walls&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The remaining 36 attempts were refused URLs, refused content, duplicates, server errors and outcomes nobody could confirm.&lt;/p&gt;

&lt;p&gt;My hard rule was that no submission may create an account — so every "sign up to submit" directory was logged and skipped, which is roughly 20 lost placements bought with a clean footprint. Image captchas were solved by taking a screenshot and reading the picture; anything demanding a phone number, social login or a hard challenge was logged as &lt;code&gt;CAPTCHA_REQUIRED&lt;/code&gt; and moved past. The 18+ site was rejected outright by general directories that do not allow adult topics — expected, but it halves the usable directory pool for that hub.&lt;/p&gt;

&lt;p&gt;The one unambiguous win was Telegraph: a published, dofollow page with an estimated DR around 90, written as a genuine checklist article rather than a link dump. Directory descriptions were unique per platform, 300–700 characters, no superlatives or rating phrasing, natural anchors, one hub URL plus one or two deep links.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free hosting is a filter, not just a saving.&lt;/strong&gt; It costs nothing to publish on &lt;code&gt;github.io&lt;/code&gt;, but monetization networks and directories check it explicitly. Decide which trade-off you want before you commit to a platform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quotas are a scheduling primitive.&lt;/strong&gt; GSC's 10/day means a 50-article batch needs five days of index requests, so batch size and index budget should be planned together instead of after publishing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep a per-attempt journal.&lt;/strong&gt; A JSONL line per submission — platform, status, DR, notes — is what makes the next round ten times faster than the first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automate the clicking, keep the rules human.&lt;/strong&gt; The agent solves image captchas, fills forms and reads journals; no fake accounts, no captcha farms and no disguising site topics stay as decisions I make once and encode in the brief.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publishing volume is not distribution.&lt;/strong&gt; With 0 impressions and 0 external links, more articles mostly add supply. Index requests, RSS, Telegram and outreach each close one specific gap — treat them as separate workstreams with their own metrics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static generation plus RSS plus Bot API covers most of the distribution stack&lt;/strong&gt;, at essentially zero recurring cost. The real spend is model tokens and review time.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>seo</category>
      <category>automation</category>
      <category>ai</category>
      <category>writing</category>
    </item>
  </channel>
</rss>
