<?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>Forem: 盛永裕介</title>
    <description>The latest articles on Forem by 盛永裕介 (@morinaga).</description>
    <link>https://forem.com/morinaga</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3907455%2F8e6a4a13-bec8-4ec0-bc2d-ec192b7880f8.png</url>
      <title>Forem: 盛永裕介</title>
      <link>https://forem.com/morinaga</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/morinaga"/>
    <language>en</language>
    <item>
      <title>I shipped a polished hanafuda card game in 2 days with Claude and Godot</title>
      <dc:creator>盛永裕介</dc:creator>
      <pubDate>Sat, 02 May 2026 13:25:12 +0000</pubDate>
      <link>https://forem.com/morinaga/i-shipped-a-polished-hanafuda-card-game-in-2-days-with-claude-and-godot-5a7j</link>
      <guid>https://forem.com/morinaga/i-shipped-a-polished-hanafuda-card-game-in-2-days-with-claude-and-godot-5a7j</guid>
      <description>&lt;p&gt;I just released &lt;a href="https://hogwartzinc.itch.io/shin-koikoi" rel="noopener noreferrer"&gt;Shin KoiKoi&lt;/a&gt; — a free, polished take on the traditional Japanese card game &lt;em&gt;Hanafuda Koi-Koi&lt;/em&gt;. Solo dev, 2 days from kickoff to itch.io public page, with full multi-language support and accessibility features.&lt;/p&gt;

&lt;p&gt;This post is a release log. I'll walk through the technical choices, what went right, and the three or four things that bit me. No hype — just what actually happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this game
&lt;/h2&gt;

&lt;p&gt;The market for hanafuda apps is bleak. Most options are ad-laden, freemium-gated, or visually frozen in 2010. I wanted a polished, fully-offline, ad-free version that respects the player. So I built one.&lt;/p&gt;

&lt;p&gt;The scope decision that made this feasible: &lt;strong&gt;only the Koi-Koi rule set&lt;/strong&gt;. No Hachi-Hachi, no Hanaawase variants, no Mushi. Single-player only for v0.1.0. Online multiplayer is planned but deferred.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Engine&lt;/td&gt;
&lt;td&gt;Godot 4.6.2 .NET (mono)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Language&lt;/td&gt;
&lt;td&gt;C# (&lt;code&gt;net9.0&lt;/code&gt; target)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI pair programming&lt;/td&gt;
&lt;td&gt;Anthropic Claude&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visual assets&lt;/td&gt;
&lt;td&gt;Gemini nanobanana2 / Midjourney V7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fonts&lt;/td&gt;
&lt;td&gt;Noto Sans CJK + Noto Sans Devanagari (OFL)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tests&lt;/td&gt;
&lt;td&gt;184 unit tests (homemade xUnit-like, all green)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Distribution&lt;/td&gt;
&lt;td&gt;itch.io Direct (Mac/Win/Linux simultaneous)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I picked Godot over Unity for three reasons: open source + zero royalties at scale, smaller binary footprint than Unity, and faster cold-edit cycle (the script-error-restart loop is much friendlier than Unity's domain reload).&lt;/p&gt;

&lt;h2&gt;
  
  
  What "2 days" actually means
&lt;/h2&gt;

&lt;p&gt;I want to be honest about the timeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pre-work&lt;/strong&gt;: ~3 weeks of design notes, scope decisions, and rule research before I touched the editor&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active dev&lt;/strong&gt;: 2 focused days of code + asset curation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Polish day&lt;/strong&gt;: itch.io setup, screenshots, multilingual descriptions, SNS announcements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So "2 days" is the interesting part — actual implementation. The pre-work matters; jumping into Godot without a scope decision would have stretched this into weeks.&lt;/p&gt;

&lt;p&gt;The 2 days included Claude writing roughly 70% of the UI scaffolding under my direction. I supplied game logic, iterations, and the "feel" decisions (animation timing, spacing, color theory). The collaboration was much closer to "principal engineer with junior pair" than "AI did it all" — Claude needed direction at every architectural decision, but the typing and boilerplate were near-instant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things that bit me
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. macOS export ETC2/ASTC requirement
&lt;/h3&gt;

&lt;p&gt;Universal binary export for macOS fails with a non-obvious error if you don't explicitly enable VRAM compression in project settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ETC2 ASTC テクスチャフォーマットが無効になっている場合、
ユニバーサルまたは arm64 用にエクスポートできません
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix is one line in &lt;code&gt;project.godot&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[rendering]&lt;/span&gt;
&lt;span class="err"&gt;textures/vram_compression/&lt;/span&gt;&lt;span class="py"&gt;import_etc2_astc&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="err"&gt;textures/vram_compression/&lt;/span&gt;&lt;span class="py"&gt;import_s3tc_bptc&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cost me 30 minutes searching the wrong way. Documenting it here so the next person Googles directly to the answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Multi-language font fallback (especially Hindi)
&lt;/h3&gt;

&lt;p&gt;Adding Devanagari (हिन्दी) to a font stack that already covers CJK and Latin requires careful priority ordering:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sysFont&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SystemFont&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;FontNames&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"Noto Sans CJK JP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"Hiragino Sans"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"Yu Gothic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"Noto Sans"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"Noto Sans Devanagari"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// ← critical for Hindi&lt;/span&gt;
        &lt;span class="s"&gt;"sans-serif"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;AllowSystemFallback&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you put &lt;code&gt;Noto Sans Devanagari&lt;/code&gt; before &lt;code&gt;Noto Sans CJK JP&lt;/code&gt;, CJK characters render with weird stroke widths. Tested all 6 languages (ja/en/de/fr/es/hi) — no missing glyphs ("tofu" boxes) anywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. AI-generated screenshot automation
&lt;/h3&gt;

&lt;p&gt;Manual screenshots are tedious and inconsistent. I wrote a Node-based state machine in C# that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initializes the Main scene&lt;/li&gt;
&lt;li&gt;Walks through Title → Game → Yaku list → Stats → Settings&lt;/li&gt;
&lt;li&gt;Captures viewport texture as PNG at each stop&lt;/li&gt;
&lt;li&gt;Quits cleanly
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;partial&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ScreenshotTour&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Node&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;_Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_stepElapsed&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_step&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_stepElapsed&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;3.0f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;Advance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Capture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"01_title.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nf"&gt;Advance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OpenSettingsForScreenshot&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="nf"&gt;Advance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="c1"&gt;// ...&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Triggered via CLI: &lt;code&gt;--screenshots /tmp/output_dir&lt;/code&gt;. Now I can re-shoot all marketing screenshots in 15 seconds whenever the UI changes. Worth the 30 minutes to write.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Oracle Cloud Always Free region trap
&lt;/h3&gt;

&lt;p&gt;Tried to use Oracle Cloud's Always Free tier for online multiplayer (Phase 2). Hit two roadblocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ARM Ampere A1.Flex shape is chronically out of capacity in Tokyo (50+ retry failures)&lt;/li&gt;
&lt;li&gt;Subscribing to other regions (Phoenix, Osaka) requires upgrading to Pay-As-You-Go — the home region is the only one available on the strict Always Free tier&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Workaround for now: ship offline-only v0.1.0 to itch.io, defer online multiplayer to v0.2 when capacity opens up or I switch hosting strategies. This was the right call — the game is complete as a single-player experience and shipping early matters more than adding multiplayer to an unproven idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI art with zero IP risk
&lt;/h2&gt;

&lt;p&gt;I generated ~45 PNG assets using Gemini nanobanana2 and Midjourney V7. All disclosed openly via itch.io's "AI generation disclosure" toggle (it's a yes/no field; I selected yes).&lt;/p&gt;

&lt;p&gt;The risk-mitigation choice that made this clean: &lt;strong&gt;no characters, no people&lt;/strong&gt;. Only:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Family crests (kamon)&lt;/li&gt;
&lt;li&gt;Hanafuda card motifs (12 months of seasonal nature imagery — public-domain cultural symbols)&lt;/li&gt;
&lt;li&gt;Backgrounds (pine, cherry blossom, moon)&lt;/li&gt;
&lt;li&gt;Rank badges (kanji on lacquered medallions)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every element is either a public-domain cultural symbol or an abstract decoration. No specific character likeness anywhere, so no IP collision risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessibility from day one
&lt;/h2&gt;

&lt;p&gt;This is non-negotiable for me. v0.1.0 ships with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Colorblind mode (deutan/protan-aware saturation tweaks)&lt;/li&gt;
&lt;li&gt;4 UI scales (0.85x / 1.0x / 1.15x / 1.30x)&lt;/li&gt;
&lt;li&gt;Reduced motion mode (shortens cutin animations)&lt;/li&gt;
&lt;li&gt;6 languages with proper script support&lt;/li&gt;
&lt;li&gt;GDPR/CCPA consent flow on first run&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Adding these later costs more than building them in upfront, and "indie casual" isn't an excuse to skip them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd do differently
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Set up automation earlier&lt;/strong&gt;: I should have written the screenshot tour and SDK install scripts in hour 1, not hour 30&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pre-build the icon set&lt;/strong&gt;: Apple/Google demand many icon sizes; using &lt;code&gt;sips&lt;/code&gt; to batch-resize would have saved 20 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test on Linux earlier&lt;/strong&gt;: I built Linux export last and discovered a permissions issue. Should have done a quick smoke test on each platform every few hours&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Roadmap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ v0.1.0 (2026-05-02): Single-player, all 3 desktop platforms, 6 languages, accessibility&lt;/li&gt;
&lt;li&gt;🔜 v0.1.1: Bug fixes from itch.io community feedback&lt;/li&gt;
&lt;li&gt;🔜 v0.2: Online multiplayer (Nakama + free server hosting once capacity opens)&lt;/li&gt;
&lt;li&gt;🔜 Mobile: Google Play ($25 one-time) and possibly App Store ($99/year if interest justifies)&lt;/li&gt;
&lt;li&gt;🔜 Steam: Landscape UI implementation first, then Steamworks Direct ($100 per submission)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://hogwartzinc.itch.io/shin-koikoi" rel="noopener noreferrer"&gt;&lt;strong&gt;Download Shin KoiKoi (free)&lt;/strong&gt;&lt;/a&gt; — Mac, Windows, Linux. No ads, no IAP, no tracking.&lt;/p&gt;

&lt;p&gt;Source isn't public yet, but if any specific subsystem (the AI evaluator, the locale system, the screenshot tour) interests folks I'm happy to write follow-up posts. Reply or DM with what you'd want.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built solo by &lt;a href="https://hogwartzinc.itch.io" rel="noopener noreferrer"&gt;hogwartz.inc&lt;/a&gt;. Engine: Godot 4.6.2. Pair programming: Anthropic Claude. Made with respect for the traditional game and for the player's time.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>godot</category>
      <category>gamedev</category>
      <category>csharp</category>
      <category>ai</category>
    </item>
    <item>
      <title>Adding 'avoid if' caveats to my AI game recommender — what changed</title>
      <dc:creator>盛永裕介</dc:creator>
      <pubDate>Fri, 01 May 2026 14:02:16 +0000</pubDate>
      <link>https://forem.com/morinaga/adding-avoid-if-caveats-to-my-ai-game-recommender-what-changed-hk3</link>
      <guid>https://forem.com/morinaga/adding-avoid-if-caveats-to-my-ai-game-recommender-what-changed-hk3</guid>
      <description>&lt;p&gt;I added a single sentence to my AI prompt for indie game recommendations: &lt;em&gt;"include one specific 'avoid if' caveat per game that mentions a real limitation."&lt;/em&gt; The output went from blandly positive to advice I'd actually trust — the kind of thing a friend who'd played the game would say.&lt;/p&gt;

&lt;p&gt;This is a 1,000-word post about why that one-line change matters more than I expected, and where it falls apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  The marketing-speak problem
&lt;/h2&gt;

&lt;p&gt;Pull up almost any indie game directory site and you'll find the same shape of copy: every game is "breathtaking", "innovative", "unforgettable". The third-party recommendation engines built on top of Steam are particularly bad at this — they default to the marketing voice of the developer's own store page.&lt;/p&gt;

&lt;p&gt;I noticed it as soon as I started building Find Games Like, the indie-games half of a three-site experiment I'm running. I was generating recommendations for ~140 indie titles using Claude Haiku 4.5, and the first batch read like the back of a Steam keyword search: lots of adjectives, zero specific information about who shouldn't play.&lt;/p&gt;

&lt;p&gt;Generic AI tone matches generic marketing tone, because both are trying to maximize the chance that any given reader thinks the product is for them. That's exactly the wrong objective for a recommendation engine. A good recommendation is most useful when it filters &lt;em&gt;out&lt;/em&gt; the wrong audience.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual prompt change
&lt;/h2&gt;

&lt;p&gt;Here's what I changed. The original prompt asked Claude to produce three reasons to recommend a game. The new version asks for the same plus one specific caveat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;For each game, write:
- 3 specific reasons someone might love it
- 1 "avoid if" caveat naming a concrete audience trait or game element
  that would make this game frustrating
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the entire change. Not even a system prompt edit — just two more lines in the user-turn instruction.&lt;/p&gt;

&lt;p&gt;The model behavior shift was bigger than the prompt size suggests. The act of having to name &lt;em&gt;who shouldn't play&lt;/em&gt; forces Claude to think about the game's actual properties rather than generating flattery. The caveat sentence then anchors the surrounding three positive sentences in something that feels real.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it produces
&lt;/h2&gt;

&lt;p&gt;Three real outputs from the current pipeline:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Celeste&lt;/strong&gt; — avoid if you're uncomfortable with themes of anxiety and panic attacks. The game's narrative is explicitly about the protagonist's mental health, and several mechanics tie difficulty spikes to representations of intrusive thoughts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hades&lt;/strong&gt; — avoid if you dislike permadeath roguelikes or need a single linear story you can finish in one sitting. Each run takes 30-50 minutes, and the narrative deliberately rewards repeated failure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hollow Knight&lt;/strong&gt; — avoid if you find punishing platforming and unforgiving boss fights frustrating. The map is intentionally cryptic and progression often requires returning to old areas after acquiring abilities you didn't know existed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Each one is specific. Each one names an actual game property a hypothetical player could check against their own preferences. None of them say "if you don't like indie games" or "if you don't like Metroidvanias", which is what a lazy version of this prompt would produce.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this works
&lt;/h2&gt;

&lt;p&gt;There's a credibility mechanic here that's older than directory sites: admitting weakness signals integrity. A recommender that only ever says good things either has bad taste or is hiding something. A recommender that says "this is great, but it's not for you if X" is making a calibrated claim — which makes the positive part of the claim more believable.&lt;/p&gt;

&lt;p&gt;The same instinct shows up in product copy when it's done well. Patagonia's "Don't Buy This Jacket" Black Friday ad is the canonical example. App Store reviews that lead with "I had to stop using this because…" are the most useful ones in the entire reviews section. Restaurant guides that explicitly note service quirks alongside food quality feel more trustworthy than ones that only star-rate.&lt;/p&gt;

&lt;p&gt;The "avoid if" pattern is just the directory-listing version of that instinct, applied at the prompt layer instead of relying on individual writers to remember to do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it breaks down
&lt;/h2&gt;

&lt;p&gt;Not every game has a meaningful caveat. Some titles are genuinely broad-appeal — short narrative games, cozy farming sims, party games for groups. Claude noticed this early in the pipeline and started inventing caveats for games that didn't really need one. The first version of &lt;em&gt;Stardew Valley&lt;/em&gt; in my data read "avoid if you don't enjoy slow-paced games", which is approximately useless.&lt;/p&gt;

&lt;p&gt;I've been adding a fallback rule to the prompt: &lt;em&gt;"if no honest caveat exists, return null for the avoid_if field rather than fabricating one."&lt;/em&gt; Compliance is around 80% — Claude still occasionally invents weak caveats — but it's better than forcing one on every entry.&lt;/p&gt;

&lt;p&gt;Two other places this technique fails:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Taste-driven domains where there's no objective basis for caveats.&lt;/strong&gt; Recommending books for a particular mood, or recommending restaurants for a particular cuisine — the caveat would be tautological ("avoid if you don't like mystery novels"). The technique needs a domain where some audience traits genuinely conflict with the product.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;When the underlying knowledge is wrong.&lt;/strong&gt; Claude once generated a caveat for &lt;em&gt;Outer Wilds&lt;/em&gt; about "puzzle complexity" when the game's actual stress point is the time-loop mechanic. Wrong-axis caveats are arguably worse than no caveats — they look authoritative while pointing the reader at a fictional concern. I haven't fully solved this; the best mitigation so far is grounding the prompt with the game's actual Steam tags and a one-paragraph manual summary before asking for the caveat.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Where to apply it beyond games
&lt;/h2&gt;

&lt;p&gt;I think the same pattern applies to almost any directory or recommendation site:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OSS alternatives to SaaS&lt;/strong&gt;: "Stay on the SaaS if your team has fewer than three engineers and no DevOps capacity."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI tools directories&lt;/strong&gt;: "Avoid this model if your workload is latency-sensitive at scale."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Restaurant guides&lt;/strong&gt;: "Skip on a date — the lighting is industrial and tables are loud."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Book recommendations&lt;/strong&gt;: "Skip if you've already read X — the thesis overlaps significantly."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What these share is a mental model where the audience has a specific trait, the product has a specific limitation, and a useful directory makes that mapping explicit instead of leaving every reader to discover it post-purchase.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm watching
&lt;/h2&gt;

&lt;p&gt;I don't have data yet on whether "avoid if" caveats actually translate into more reader trust. Find Games Like is eight days old and traffic is essentially zero — I'll publish real engagement numbers (comments, time on page, return visits) at the 30-day mark.&lt;/p&gt;

&lt;p&gt;The falsifiable claim is: pages with caveats should outperform pages without them on engagement metrics. If that turns out to be wrong by month two, I'll need to revisit the assumption that honesty-as-trust-signal works in directory contexts the way it works in book reviews.&lt;/p&gt;

&lt;p&gt;Until then: every AI-generated recommendation I add to that site has a caveat. The prompt is two extra lines. The output reads like advice from someone who's actually played the game.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Part of an ongoing 6-month experiment running three AI-curated directory sites. The technical claims here are real; this article was AI-assisted.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>indiehackers</category>
      <category>programming</category>
    </item>
    <item>
      <title>I built 3 programmatic SEO sites for $25/month using Claude Haiku — here's the full architecture</title>
      <dc:creator>盛永裕介</dc:creator>
      <pubDate>Fri, 01 May 2026 11:59:13 +0000</pubDate>
      <link>https://forem.com/morinaga/i-built-3-programmatic-seo-sites-for-25month-using-claude-haiku-heres-the-full-architecture-3pl8</link>
      <guid>https://forem.com/morinaga/i-built-3-programmatic-seo-sites-for-25month-using-claude-haiku-heres-the-full-architecture-3pl8</guid>
      <description>&lt;p&gt;Spent the past week running an experiment: can a programmatic SEO directory site survive Google's 2024 Helpful Content Update if every page is AI-generated?&lt;/p&gt;

&lt;p&gt;Rather than pick one niche and bet the farm, I built &lt;strong&gt;three&lt;/strong&gt; parallel sites with the same stack — different content categories, identical architecture, single content generation pipeline. They share a monorepo, deploy independently to Vercel, and refresh nightly via one GitHub Actions cron.&lt;/p&gt;

&lt;p&gt;This post is the architecture write-up. I'll publish actual revenue/traffic numbers in a follow-up after 6 months.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three sites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🤖 &lt;strong&gt;&lt;a href="https://topaitools.vercel.app" rel="noopener noreferrer"&gt;Top AI Tools&lt;/a&gt;&lt;/strong&gt; — ~500 open-source models from HuggingFace, with Claude-generated summaries, use cases, and FAQ&lt;/li&gt;
&lt;li&gt;🎮 &lt;strong&gt;&lt;a href="https://findgameslike.vercel.app" rel="noopener noreferrer"&gt;Find Games Like&lt;/a&gt;&lt;/strong&gt; — "games like X" recommendations for indie titles on Steam, with AI-curated similarity reasoning and "avoid if" caveats&lt;/li&gt;
&lt;li&gt;🛠 &lt;strong&gt;&lt;a href="https://openalternativeto.vercel.app" rel="noopener noreferrer"&gt;Open Alternative To&lt;/a&gt;&lt;/strong&gt; — open-source replacements for ~80 popular SaaS products, refreshed daily from GitHub stars and last-pushed timestamps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three are static-generated, all three rebuild nightly, all three share editorial logic from a single TypeScript package.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why three sites instead of one
&lt;/h2&gt;

&lt;p&gt;Three reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cheap insurance against niche choice failure.&lt;/strong&gt; I don't know which niche Google will tolerate in 2026. Three uncorrelated bets &amp;gt; one big one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared ETL infrastructure.&lt;/strong&gt; The cost of running site #2 and #3 is mostly the marginal Claude API tokens (~$2/site/month). Hosting and code is amortized.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A/B testing categories.&lt;/strong&gt; AI-tools is the most saturated PSEO niche on Earth. SaaS-alternative goes head-to-head with alternativeto.net (DA80+, 20 years authority). Indie games is the underdog with the cleanest niche fit. After 6 months, the data tells me which thesis was right.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Stack at a glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Site framework&lt;/td&gt;
&lt;td&gt;Astro 5 (SSG)&lt;/td&gt;
&lt;td&gt;100% static output, no runtime cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Styling&lt;/td&gt;
&lt;td&gt;Tailwind v4&lt;/td&gt;
&lt;td&gt;Newer engine, faster builds, smaller CSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content gen&lt;/td&gt;
&lt;td&gt;Claude Haiku 4.5 via Anthropic SDK&lt;/td&gt;
&lt;td&gt;Cheap, fast, sufficient for directory copy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data store&lt;/td&gt;
&lt;td&gt;Turso (libSQL)&lt;/td&gt;
&lt;td&gt;ETL state + idempotency tracking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cron&lt;/td&gt;
&lt;td&gt;GitHub Actions matrix job&lt;/td&gt;
&lt;td&gt;Free, version-controlled, reliable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting&lt;/td&gt;
&lt;td&gt;Vercel Pro&lt;/td&gt;
&lt;td&gt;Fast SSG deploys, image optimization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monorepo&lt;/td&gt;
&lt;td&gt;pnpm + Turborepo&lt;/td&gt;
&lt;td&gt;Workspace-aware builds, cached output&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Total monthly cost
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vercel Pro&lt;/td&gt;
&lt;td&gt;$20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic API (Haiku 4.5, daily refresh)&lt;/td&gt;
&lt;td&gt;~$5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Turso (free tier 500MB)&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Actions (under 2k min/mo free quota)&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domains (Vercel subdomains until validation)&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$25/month&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Repo layout
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;seo-farm/
├── apps/
│   ├── ai-tools/          # topaitools.vercel.app
│   ├── indie-games/       # findgameslike.vercel.app
│   ├── oss-alternatives/  # openalternativeto.vercel.app
│   └── dashboard/         # internal status page
├── packages/
│   ├── shared/            # Anthropic client, DB schema, monetization helpers
│   └── publish/           # the script that posted this article
└── .github/workflows/
    └── refresh-content.yml  # nightly cron
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The three sites are intentionally &lt;strong&gt;separate Vercel projects&lt;/strong&gt; (different roots), but share &lt;code&gt;@seo-farm/shared&lt;/code&gt; for the Claude client, libSQL helpers, AdSense + Amazon affiliate components, and structured-data builders. Each site has its own ETL — HuggingFace API for ai-tools, Steam Web API + RAWG for indie-games, GitHub repo discovery for oss-alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Content generation pipeline
&lt;/h2&gt;

&lt;p&gt;The cron runs daily at 02:00 UTC and processes one app at a time (matrix &lt;code&gt;max-parallel: 1&lt;/code&gt; to stay below Anthropic burst limits):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ai-tools&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;indie-games&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;oss-alternatives&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;max-parallel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ETL_LIMIT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;500"&lt;/span&gt;
  &lt;span class="na"&gt;GENERATE_LIMIT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;300"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Per app, the pipeline is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;ETL stage&lt;/strong&gt; — fetch source data (HuggingFace models / Steam games / GitHub repos), upsert into Turso&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detect missing content&lt;/strong&gt; — find rows where &lt;code&gt;generated_at&lt;/code&gt; is null or older than 30 days&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate with Haiku 4.5&lt;/strong&gt; — batch ~5 entries per call, one prompt per content type&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache &amp;amp; dedupe&lt;/strong&gt; — write back to Turso with new &lt;code&gt;generated_at&lt;/code&gt; timestamp&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trigger build&lt;/strong&gt; — only if content changed, push commit and let Vercel rebuild&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The hard part is &lt;strong&gt;step 3 prompt design&lt;/strong&gt;. Generic "summarize this tool" prompts produce slop. What worked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One prompt per content type&lt;/strong&gt; (summary / use cases / FAQ / pros-cons), never a single mega-prompt&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strict format constraints&lt;/strong&gt; ("3-5 bullet points, max 12 words each, no marketing language")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source-grounded context&lt;/strong&gt; — only use info from the provided model card; refuse to fabricate benchmarks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An "avoid if" caveat for game recs&lt;/strong&gt; — most game directories only gush. Find Games Like prompt explicitly asks Claude to be honest about limitations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Find Games Like, the "avoid if" produces lines like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Celeste — avoid if you're uncomfortable with themes of anxiety and panic attacks&lt;br&gt;
Hades — avoid if you dislike permadeath roguelikes or need linear story progression&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's one of the few moments AI summaries actually beat human-written game directories, which all default to marketing-speak.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ranking strategy (or: things Google may kill anyway)
&lt;/h2&gt;

&lt;p&gt;I'm not delusional about this. Google's March 2024 update specifically targeted "scaled content abuse" and de-indexed thousands of programmatic SEO sites. The bet here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Source-grounded content&lt;/strong&gt; — every detail page links to canonical authoritative source (HuggingFace model card, Steam store page, GitHub repo). Reader can verify in one click.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real utility&lt;/strong&gt; — directory + comparison tables that genuinely save time vs reading 30 docs pages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Honest framing&lt;/strong&gt; — "AI-generated, here's the source" disclosed in footer, no hiding&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-page structured data&lt;/strong&gt; — &lt;code&gt;SoftwareApplication&lt;/code&gt;, &lt;code&gt;VideoGame&lt;/code&gt;, &lt;code&gt;Product&lt;/code&gt; JSON-LD on every detail page&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low quantity, daily freshness&lt;/strong&gt; — 880 total pages, refreshed daily so star counts and modification dates stay current. Not 100k pages of stale garbage.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I genuinely don't know if any of this is enough. The whole point of the experiment is to find out. If two of three sites get deindexed by month 3, that itself is a useful data point.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's wired up
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AdSense&lt;/strong&gt; site-wide (currently in review — sites are &amp;lt;2 weeks old)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Associates&lt;/strong&gt; with category-relevant search links per page (no fake recs, just &lt;code&gt;amzn.to&lt;/code&gt; search-by-keyword links to actual related books/peripherals)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GA4&lt;/strong&gt; per site with separate properties&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Newsletter&lt;/strong&gt; via Beehiiv iframe ("Indie Discovery Weekly")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sitemaps + robots.txt + llms.txt&lt;/strong&gt; generated at build time&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Milestones I'm watching
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Month&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Threshold&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Did Google index the pages?&lt;/td&gt;
&lt;td&gt;Search Console impressions &amp;gt;1k/day = yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Is organic traffic growing?&lt;/td&gt;
&lt;td&gt;&amp;gt;50% organic share of GA4 sessions = healthy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Is monetization viable?&lt;/td&gt;
&lt;td&gt;AdSense approved, RPM measurable, decision: delete or double down&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Is it sellable?&lt;/td&gt;
&lt;td&gt;3 consecutive months of profit &amp;gt; 0 = list on Empire Flippers / similar&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Open questions for readers
&lt;/h2&gt;

&lt;p&gt;I'd genuinely value feedback on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;PSEO survivors of March 2024&lt;/strong&gt; — what categories are still ranking?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema markup&lt;/strong&gt; — am I missing anything obvious for directory sites?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI content disclosure&lt;/strong&gt; — how transparent is too transparent? Does the footer "AI-generated" disclosure help or hurt?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Niche durability&lt;/strong&gt; — which of the three do you think survives 12 months? Place your bets.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Repo isn't public yet — I might open source it after the 6-month checkpoint depending on how the experiment goes. Happy to share specific snippets in the comments if anyone's curious about a particular piece (Astro content collection layout, the Claude prompts, the structured-data helper, the Vercel Pro deploy config).&lt;/p&gt;

&lt;p&gt;Next update in 30 days with actual numbers, regardless of how ugly they look.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>astro</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
