<?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: Mike “Demo” Demopoulos</title>
    <description>The latest articles on DEV Community by Mike “Demo” Demopoulos (@mpmike).</description>
    <link>https://dev.to/mpmike</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%2F389717%2Fa648f865-55d3-4e9f-98cf-e832c4d376a2.jpg</url>
      <title>DEV Community: Mike “Demo” Demopoulos</title>
      <link>https://dev.to/mpmike</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mpmike"/>
    <language>en</language>
    <item>
      <title>Did It Move? An ambient haunting that costs $6.12 an hour, so I made it cost cents</title>
      <dc:creator>Mike “Demo” Demopoulos</dc:creator>
      <pubDate>Sat, 31 Oct 2026 03:06:01 +0000</pubDate>
      <link>https://dev.to/mpmike/did-it-move-an-ambient-haunting-that-costs-612-an-hour-so-i-made-it-cost-cents-280k</link>
      <guid>https://dev.to/mpmike/did-it-move-an-ambient-haunting-that-costs-612-an-hour-so-i-made-it-cost-cents-280k</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week4-2026-10-26"&gt;Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Did It Move?&lt;/strong&gt; is an ambient haunting designed for the biggest, dumbest screen in the house: the TV.&lt;/p&gt;

&lt;p&gt;Open it fullscreen and forget it exists. A cozy living room — fire going, rain on the window, a portrait, a rocking chair, a candle — sits quietly for minutes at a time. Then, for a few seconds, something subtly wrong happens. The portrait's eyes are looking somewhere new. A shadow crosses the window that no one casts. The rocking chair rocks itself, gently, and stops facing the other way.&lt;/p&gt;

&lt;p&gt;When it's over, exactly one thing in the room is different from before — and the room's own event log, timestamped, insists nothing happened:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;9:42 PM — That picture has hung crooked since October.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;10:17 PM — Books fall. Gravity is not a haunting.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The horror isn't a jump scare. It's the argument you'll have with the person next to you on the couch: &lt;em&gt;I'm sure that candle was lit.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Live demo: &lt;a href="https://did-it-move.space.fast/" rel="noopener noreferrer"&gt;https://did-it-move.space.fast/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/fhNsyiQUEg0" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Try &lt;strong&gt;Demo pace&lt;/strong&gt; in the live demo — bursts arrive every ~15 seconds instead of every 4–7 minutes, because judges, unlike ghosts, are busy.&lt;/p&gt;

&lt;p&gt;And here is the full hour the room can haunt, if you have a TV and an evening:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/X2O1X_h_zHU" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Mike-Demo" rel="noopener noreferrer"&gt;
        Mike-Demo
      &lt;/a&gt; / &lt;a href="https://github.com/Mike-Demo/did-it-move" rel="noopener noreferrer"&gt;
        did-it-move
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Did It Move? — a haunted living room for DEV Hacktoberfest Week 4 'Ghost in the Machine'. CSS room, generative video bursts, and a gaslight layer that denies everything.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Did It Move?&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;An ambient haunting for smart TVs and large monitors, built for the
&lt;a href="https://dev.to/challenges/hacktoberfest-week4-2026-10-26" rel="nofollow"&gt;DEV Hacktoberfest Week 4 challenge — "Ghost in the Machine"&lt;/a&gt;
(deadline: October 31, 2026, 11:59 PM PDT).&lt;/p&gt;
&lt;p&gt;Open it fullscreen on a TV and forget it. A cozy living room — fireplace
rain on the window, a portrait, a rocking chair — sits quietly for minutes
at a time. Then, for a few seconds, something subtly wrong happens. When
it's over, one thing in the room is different from before, and the room's
log insists nothing happened at all.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Did the portrait always look toward the sofa? Has that picture always
hung crooked? You can't prove it didn't.&lt;/em&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why it isn't just "run a real-time model all evening"&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Real-time video models (here: Reactor's &lt;code&gt;xmax-x2-1&lt;/code&gt;, a streaming
video-to-video model) bill for &lt;strong&gt;session time&lt;/strong&gt;, not for interesting
moments. Checked live on 2026-10-28 against Reactor's public…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Mike-Demo/did-it-move" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The idea vs. the invoice
&lt;/h3&gt;

&lt;p&gt;The obvious way to build this is a real-time generative video model — I prototyped against Reactor's &lt;code&gt;xmax-x2-1&lt;/code&gt;, a streaming video-to-video model whose SDK (&lt;code&gt;@reactor-models/xmax-x2-1&lt;/code&gt;) lets you feed it a source stream, set a prompt, and re-render the world as it happens. Feed it the quiet room, prompt &lt;em&gt;"the portrait's eyes shift, slowly"&lt;/em&gt;, and the room haunts itself.&lt;/p&gt;

&lt;p&gt;Then I checked the pricing endpoint. Reactor charges &lt;strong&gt;$0.0017 per session-second&lt;/strong&gt; for this model — $6.12 an hour — billed from the moment a session is ready, &lt;em&gt;including while it sits idle&lt;/em&gt;, per viewer. My quiet room is idle 99% of the time, by design. The naive version costs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$48.96 for one Halloween evening on one TV&lt;/li&gt;
&lt;li&gt;~$147 a day if you leave it on&lt;/li&gt;
&lt;li&gt;an unbounded amount the moment you post a public demo link, because every visitor holds their own GPU session&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole project became: &lt;strong&gt;how do you build an ambient generative piece when generation is priced per second and ambience is priced per hour?&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The hybrid: generate the moments, not the room
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Idle layer (99% of the time, $0).&lt;/strong&gt; The room itself is hand-built CSS/SVG — fire, rain, moonlight. It can run on a TV forever for free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Burst layer (5–8 seconds).&lt;/strong&gt; A generative session exists &lt;em&gt;only&lt;/em&gt; while something is happening: a 120-second hard cap, a non-recoverable disconnect (a recoverable one keeps billing — read the docs, learn from my near-miss), and a daily budget kill-switch. At a ~2% duty cycle, a live evening costs cents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public mode ($0 per visitor).&lt;/strong&gt; The bursts used by the public demo were captured once, during development, and are replayed. The HUD shows each burst's &lt;em&gt;would-be&lt;/em&gt; live cost as a shadow price, so the economics stay visible instead of hidden.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gaslight layer ($0, and the actual joke).&lt;/strong&gt; The lasting changes — crooked picture, dead candle, turned chair — are cheap DOM state. The most memorable part of the piece costs nothing at all, which is rather the point.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The app itself is vanilla HTML/CSS/JS, no build step, no assets — it has to run in whatever browser a smart TV shipped with. The cost guardrails live in one file, &lt;code&gt;reactor-live.js&lt;/code&gt;, and the burst prompts for each event live next to their pre-recorded fallbacks in &lt;code&gt;app.js&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Two honest answers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The swap test.&lt;/strong&gt; Because Reactor hosts several models behind one SDK, I could price the closed &lt;code&gt;xmax-x2-1&lt;/code&gt; against the open-weight &lt;code&gt;sana-streaming&lt;/code&gt; and &lt;code&gt;longlive-v2&lt;/code&gt; — and they are listed at the &lt;em&gt;identical&lt;/em&gt; $0.0017/sec. When open weights cost the same as a closed model, "we can't afford to go open" stops being an argument; the decision becomes about control, longevity, and whether your ambient ghost still works the day a vendor changes its pricing page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The exit door.&lt;/strong&gt; The burst prompts are plain text, the room is open code, and nothing in the piece depends on one vendor's session: a burst is a burst whether a hosted model renders it live, a local model renders it later, or — as in the public demo — it was rendered once and kept. Open models and open code are what let a $6.12-an-hour idea become a piece that can live on a TV, in a repo, after the hackathon, for free.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Spirit of It
&lt;/h2&gt;

&lt;p&gt;The moment it landed wasn't technical. It was the first full run on the TV, when the candle went out during a quiet stretch and the room's log — deadpan, timestamped — explained that the candle had &lt;em&gt;always&lt;/em&gt; been unlit. Two people on the couch immediately disagreed about whether it had ever been lit at all. Neither could prove it. The room could. It just wouldn't.&lt;/p&gt;

&lt;p&gt;That's the haunting I wanted: not a monster, but a small, polite, well-documented doubt that follows you out of the room.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;Overall&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>I rebuilt a 7,199-game queer arcade in WordPress in five days, driving Elementor through its MCP. Every prompt is published.</title>
      <dc:creator>Mike “Demo” Demopoulos</dc:creator>
      <pubDate>Thu, 29 Oct 2026 02:08:08 +0000</pubDate>
      <link>https://dev.to/mpmike/i-rebuilt-a-7199-game-queer-arcade-in-wordpress-in-five-days-driving-elementor-through-its-mcp-19fg</link>
      <guid>https://dev.to/mpmike/i-rebuilt-a-7199-game-queer-arcade-in-wordpress-in-five-days-driving-elementor-through-its-mcp-19fg</guid>
      <description>&lt;p&gt;QueerCade is a community vault of LGBTQ+ games. It lived as a work-in-progress site at queercade.mikedemo.dev, and last week I rebuilt it properly in WordPress at &lt;a href="https://queercade.gay" rel="noopener noreferrer"&gt;queercade.gay&lt;/a&gt;: a searchable archive of &lt;strong&gt;7,199 games&lt;/strong&gt;, an interactive constellation of &lt;strong&gt;876 queer characters&lt;/strong&gt; and 1,788 connections between them, an emoji oracle that recommends your next game, and member libraries for tracking what you own and what you have played.&lt;/p&gt;

&lt;p&gt;The rebuild took five days, October 22 to 27. This week I submitted it to two showcases: the &lt;a href="https://elementor.com/showoff/" rel="noopener noreferrer"&gt;Elementor Showoff&lt;/a&gt; (in a day ahead of the deadline) and &lt;a href="https://wpshowoff.com/submit/" rel="noopener noreferrer"&gt;WP Showoff&lt;/a&gt;, where it is now waiting on a hand review.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1mkjfem03b5j1dlf9bsh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1mkjfem03b5j1dlf9bsh.png" alt="The QueerCade home page and hero" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The 54-second tour (this is also the homepage hero video):&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://videopress.com/v/E5Apx9SN" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fvideos.files.wordpress.com%2FE5Apx9SN%2Fqueercade-showoff-sizzle-4k-v3_mp4.scrubthumb.jpg" height="450" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://videopress.com/v/E5Apx9SN" rel="noopener noreferrer" class="c-link"&gt;
            QueerCade — Every Queer Game. One Arcade.
          &lt;/a&gt;
        &lt;/h2&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsecure.gravatar.com%2Fblavatar%2Fd829502dd780a0215fe1fb6ba536d78c%3Fs%3D32" width="32" height="32"&gt;
          videopress.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Watch: &lt;a href="https://videopress.com/v/E5Apx9SN" rel="noopener noreferrer"&gt;https://videopress.com/v/E5Apx9SN&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The interesting part is how it got built, and I want to be precise about that, because "AI built my website" claims are getting sloppy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rules I set
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I designed the site myself, in Google Stitch: 13 screens, one design system, no placeholder data in any of them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6vufe4qm9gji1fadgjug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6vufe4qm9gji1fadgjug.png" alt="The 13 Stitch design screens" width="799" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The designed pages were built through the official &lt;strong&gt;Elementor MCP&lt;/strong&gt;, on &lt;strong&gt;free Elementor only&lt;/strong&gt;. No Pro license hiding in the stack.&lt;/li&gt;
&lt;li&gt;Everything a designed page cannot do lives in a custom plugin I built for the site, QueerCade Connect (v0.46.16 as of this writing): the catalog mirror, the constellation, the oracle, member tracking and personal collections, social sign-in, the works.&lt;/li&gt;
&lt;li&gt;Jetpack does the jobs Jetpack is good at: Search, VideoPress, Boost, the newsletter. WordPress core does the rest.&lt;/li&gt;
&lt;li&gt;The catalog data still lives in Sanity. WordPress mirrors it; Sanity stays the source of truth.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The receipts
&lt;/h2&gt;

&lt;p&gt;I published the whole build trail in a public Gist: every prompt I sent, plus the site's sanitized WordPress activity log for the build window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://gist.github.com/Mike-Demo/3bc5d9967aa91e04df5c72ebf750eec0" rel="noopener noreferrer"&gt;QueerCade build prompts and activity log (Gist)&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Numbers from that log:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;34,261 activity events&lt;/strong&gt; across five days (29,324 of them REST API calls)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;9 prompts&lt;/strong&gt; built the first 9 designed pages in a single evening; the first Home composition alone placed 54 elements&lt;/li&gt;
&lt;li&gt;Catalog grew &lt;strong&gt;753 → 7,199 games&lt;/strong&gt; in one approval pass; 3,290 covers sideloaded in 344 batches with 0 errors&lt;/li&gt;
&lt;li&gt;Media library metadata finished at &lt;strong&gt;4,245 attachments, zero missing alt text, captions, or descriptions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Schema validation sweep: &lt;strong&gt;7,207 URLs checked, 0 with errors&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;GTmetrix (Chicago): main pages scoring in the high 80s and 90s for Performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F93u8i19ynkq4644btsny.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F93u8i19ynkq4644btsny.png" alt="QueerCade by the numbers" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The constellation, with Ellie from The Last of Us selected:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbzpj0di632bu7ucpc0ff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbzpj0di632bu7ucpc0ff.png" alt="The character constellation with Ellie's dossier open" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the emoji oracle:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp1n4e9g3d9dnb8hzz0zv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp1n4e9g3d9dnb8hzz0zv.png" alt="The Emoji Oracle" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The long-form version of the story, with video, is the X article I wrote for the Elementor submission:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2115574081839853866-312" src="https://platform.twitter.com/embed/Tweet.html?id=2115574081839853866"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2115574081839853866-312');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2115574081839853866&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h2&gt;
  
  
  What the MCP could not do (the honest friction)
&lt;/h2&gt;

&lt;p&gt;Driving a page builder through an MCP server works better than I expected, and it is not magic. Three things worth knowing if you try this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Verify persistence, not success messages.&lt;/strong&gt; The Elementor MCP's element update operations sometimes reported success while the change did not persist. Later design edits rode WordPress REST patches to &lt;code&gt;_elementor_data&lt;/code&gt; instead, followed by Elementor's Clear Files &amp;amp; Data, because Elementor serves a compiled render.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A generated revision is not your live page.&lt;/strong&gt; One MCP pass wrote its hero work into a revision whose round-trip also stripped styles from unrelated elements. The shipped pattern: take the node the MCP generated, splice it into the pristine live document over REST, then clear the cache. Check the diff before anything goes live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Some fixes belong below the builder.&lt;/strong&gt; The homepage hero video wanted to preload 41 MB. The builder's settings schema has no preload control, so the plugin rewrites the rendered tag at the PHP output-buffer level (&lt;code&gt;preload="none"&lt;/code&gt;, load on hover, play on click). Homepage weight dropped from ~43.6 MB to ~2.3 MB.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every cornerstone page was captured across 9 device and browser configurations before launch, 126 captures in the full matrix:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fklflkogi3vnri2qbu897.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fklflkogi3vnri2qbu897.png" alt="The home page across 9 BrowserStack configurations" width="800" height="1031"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Watch the build
&lt;/h2&gt;

&lt;p&gt;The five-day build, compressed to 70 seconds:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://videopress.com/v/cSIt73FS" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fvideos.files.wordpress.com%2FcSIt73FS%2Fqueercade-showoff-timeline-4k-scored_mp4.scrubthumb.jpg" height="450" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://videopress.com/v/cSIt73FS" rel="noopener noreferrer" class="c-link"&gt;
            Six Days. One Vault. — Building QueerCade, Oct 22–27
          &lt;/a&gt;
        &lt;/h2&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsecure.gravatar.com%2Fblavatar%2Fd829502dd780a0215fe1fb6ba536d78c%3Fs%3D32" width="32" height="32"&gt;
          videopress.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Watch: &lt;a href="https://videopress.com/v/cSIt73FS" rel="noopener noreferrer"&gt;https://videopress.com/v/cSIt73FS&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the before and after, template site to arcade vault:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://videopress.com/v/kiK3zZxR" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fvideos.files.wordpress.com%2FkiK3zZxR%2Fqueercade-showoff-before-after-1_mp4.scrubthumb.jpg" height="450" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://videopress.com/v/kiK3zZxR" rel="noopener noreferrer" class="c-link"&gt;
            QueerCade Before &amp;amp; After — From Template Site to Arcade Vault
          &lt;/a&gt;
        &lt;/h2&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsecure.gravatar.com%2Fblavatar%2Fd829502dd780a0215fe1fb6ba536d78c%3Fs%3D32" width="32" height="32"&gt;
          videopress.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Watch: &lt;a href="https://videopress.com/v/kiK3zZxR" rel="noopener noreferrer"&gt;https://videopress.com/v/kiK3zZxR&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The disclosure part
&lt;/h2&gt;

&lt;p&gt;WP Showoff asks every submission how AI was used: AI Generated, AI Assisted, or No AI. I picked &lt;strong&gt;AI Assisted&lt;/strong&gt;, because that is the truth of this build. A human designed it, directed it, wrote the plugin that runs it, and reviewed every change. An AI agent held the mouse for a large share of the page building, and hiding that would be worse than saying it.&lt;/p&gt;

&lt;p&gt;If the receipts make one argument, it is this: the interesting question is no longer whether AI helped build a site. It is whether the builder can show their work.&lt;/p&gt;

&lt;p&gt;QueerCade is live at &lt;a href="https://queercade.gay" rel="noopener noreferrer"&gt;queercade.gay&lt;/a&gt;. Go find your next game.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>elementor</category>
      <category>ai</category>
      <category>devpride</category>
    </item>
    <item>
      <title>I Built a Job Search App That Fights You Back — Because Slow and Steady Is the Only Strategy That Lasts</title>
      <dc:creator>Mike “Demo” Demopoulos</dc:creator>
      <pubDate>Wed, 21 Oct 2026 02:13:48 +0000</pubDate>
      <link>https://dev.to/mpmike/i-built-a-job-search-app-that-fights-you-back-because-slow-and-steady-is-the-only-strategy-that-3mc4</link>
      <guid>https://dev.to/mpmike/i-built-a-job-search-app-that-fights-you-back-because-slow-and-steady-is-the-only-strategy-that-3mc4</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;The sloth moves at its own pace. It conserves energy. It survives. It has never once refreshed an applicant portal at 2 a.m.&lt;/p&gt;

&lt;p&gt;Black Box is a job search app built in the sloth's honour — which means it is a job search app that deliberately slows you down. Every other tool in this space tries to make you faster: more applications, more alerts, more dashboards to check. Black Box does the opposite, on purpose, with mechanics instead of advice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Vault.&lt;/strong&gt; Your application statuses stay shut until one daily opening, and a short breathing pause (in for 4, hold for 4, out for 4) stands between you and the reveal. Once a day turns out to be enough — the statuses are the same whether you check once or twenty times; only the cost to you changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A daily application budget.&lt;/strong&gt; You set a small number. When it's spent, the app stops for the day, and says so plainly: that's the whole job for today; the rest of the day is yours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A 48-hour draft hold.&lt;/strong&gt; A role you add today cannot be marked applied for two days. If it still looks right in 48 hours, it was worth applying to. Most impulse applications don't survive the hold — which is the hold working.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A Gemma quality score.&lt;/strong&gt; Paste a job description and Gemma scores it 1–10 against &lt;em&gt;your&lt;/em&gt; stated profile, with its reasons shown. A low score is information, not a verdict.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A calm reframe.&lt;/strong&gt; Paste a hard-to-read outcome notice. Gemma restates it in plainer words and separates what it actually decided, what it states, what it does &lt;em&gt;not&lt;/em&gt; say, and one factual next step. Your original text stays on screen, word for word, next to the reframe — the reframe is labelled, and it never replaces the original.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An application-email inbox.&lt;/strong&gt; Sign in with email and application messages come into Black Box instead of your regular inbox — and then they wait, like everything else here. Mail is only shown inside the daily vault window; anything that arrives after the window is held for the next one. No pushes, no badges, no 9 p.m. rejection ambush. Open a message and you get its original words first, with the Gemma reframe as an optional second reading. &lt;strong&gt;Honest demo note:&lt;/strong&gt; in this build the sign-in link is simulated — no email is actually sent and no server account exists — and the inbox holds sample messages, so the whole flow can be exercised end to end. The mechanics (mail waits for your window) are real; a production version connects a real mailbox behind the same screens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A mood check-in on a scale.&lt;/strong&gt; A slider from Rough to Good — the shape borrowed from Voda's daily wellbeing check-in — with the word you chose read back in plain language and a quiet 7-day trend. It is self-report only; the app never guesses how you feel. No streaks, no judgement. A mark for today, if you want one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progress cards.&lt;/strong&gt; Achievements, but only for the slow behaviours the app exists to protect: saving a first draft to the hold, waiting the full 48 hours, letting a draft go, spending the budget and then actually stopping, reading mail inside the window. Cards record process, never outcomes — an interview is not a card, and nothing earned can be lost. It is a record of restraint, not a scoreboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Who gets to be lazier because of this? Anyone in a long job search who is spending their limited energy on checking instead of living. Black Box's whole job is to give that time back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Live demo: &lt;a href="https://black-box-sy5x.onrender.com" rel="noopener noreferrer"&gt;https://black-box-sy5x.onrender.com&lt;/a&gt;&lt;/strong&gt; (Render Starter plan — always on, no wake-up wait)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fastest way in: &lt;a href="https://black-box-sy5x.onrender.com/demo" rel="noopener noreferrer"&gt;https://black-box-sy5x.onrender.com/demo&lt;/a&gt;&lt;/strong&gt; — a one-click demo account that seeds a week of sample applications, inbox mail, and mood marks into your browser and signs you in as &lt;a href="mailto:demo@mikedemo.email"&gt;demo@mikedemo.email&lt;/a&gt;, so the vault, the reframe, and the progress cards can all be exercised immediately. It's sample data, it lives only in your browser, and the app says so.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The full walkthrough — 100 seconds, breathing gate and all:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/taNaIRyd-Ro" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And the breathing gate as a standalone minute&lt;/strong&gt; — the cover sloth, animated, with a guided 4 · 4 · 4:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/fCtUhRa4KGk" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The demo runs in "Demo mode": hosted Gemma 4, clearly labelled in the interface, because Render has no GPU. Run it locally (instructions in the repo) and the same code calls Gemma on your own machine instead — see below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Mike-Demo" rel="noopener noreferrer"&gt;
        Mike-Demo
      &lt;/a&gt; / &lt;a href="https://github.com/Mike-Demo/black-box" rel="noopener noreferrer"&gt;
        black-box
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Black Box — a job search app that slows you down on purpose. DEV Hacktoberfest Week 3: Slow and Steady. Gemma 4 local-first, deployed on Render.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Black Box 🦥&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;A job search app that slows you down on purpose.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Live demo: &lt;a href="https://black-box-sy5x.onrender.com" rel="nofollow noopener noreferrer"&gt;https://black-box-sy5x.onrender.com&lt;/a&gt;&lt;/strong&gt; (Render Starter plan — always on)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One-click demo account: &lt;a href="https://black-box-sy5x.onrender.com/demo" rel="nofollow noopener noreferrer"&gt;https://black-box-sy5x.onrender.com/demo&lt;/a&gt;&lt;/strong&gt; — seeds a week of sample applications, inbox mail, and mood marks into your browser and signs you in as &lt;a href="mailto:demo@mikedemo.email"&gt;demo@mikedemo.email&lt;/a&gt;, so the whole app (vault, reframe, progress cards) can be exercised immediately. Sample data only; it never leaves your browser.&lt;/p&gt;
&lt;p&gt;Built for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19" rel="nofollow"&gt;DEV Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt; — build something with open-source AI that rewards laziness.&lt;/p&gt;
&lt;p&gt;Every job search tool tries to make you go faster: more applications, more refreshing, more dashboards. Black Box does the opposite. It is named for the flight recorder — the box you only open when it matters — and for the closed lid it puts between you and compulsive status-checking.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What it does&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Vault&lt;/strong&gt; — Application statuses stay shut…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Mike-Demo/black-box" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;One small Next.js app (App Router, TypeScript, Tailwind). No database. No server accounts. No analytics. Every piece of user data — applications, vault state, budget, mood log, profile, inbox, and the demo session — lives in the browser's local storage, on the user's machine.&lt;/p&gt;

&lt;p&gt;The UX was designed before it was built, twice. First I gave Google Stitch this repo plus the &lt;code&gt;DESIGN.md&lt;/code&gt; from my open-source &lt;a href="https://github.com/Mike-Demo/happy-code-library/tree/main/.stitch" rel="noopener noreferrer"&gt;happy-code-library&lt;/a&gt; (the Web Awesome design system), created the design system in Stitch from that file, and generated the screens — email sign-in, the Today dashboard, the Vault with its inbox, the email reframe detail, and a check-in &amp;amp; progress screen. Then, after using the app for a day, I asked Stitch for redesigns with &lt;em&gt;no&lt;/em&gt; design system attached, taking the whole aesthetic from Voda (the LGBTQIA+ wellbeing app) instead. It came back with two — a pastel daylight version and a dusk version — and I picked daylight: the shipped app is rebuilt toward it, with a warm cream background, a soft serif for headlines and greetings, pastel-tinted cards, and one deep indigo for actions. The design exports and both explorations live in the repo under &lt;code&gt;design/&lt;/code&gt;. The restyle also replaced the mood emoji with plain words (Rough / Tiring / Neutral / Steady / Good) — plainer is calmer — and a later design pass turned the mood check-in into a gradient scale and added the progress cards, taking the shape of both from Voda's daily check-in and journey cards. The scale's handle is an emoji face that changes expression along the scale — a sloth when the day is unmarked — because one expressive exception earned its place; the words themselves stay plain.&lt;/p&gt;

&lt;p&gt;The calm isn't only an aesthetic. The design is checked against Microsoft's Inclusive Design guidance for mental health — the &lt;a href="https://inclusive.microsoft.design/articles/mental-health-guidebook" rel="noopener noreferrer"&gt;Mental Health Guidebook&lt;/a&gt; and its &lt;a href="https://inclusive.microsoft.design/articles/mental-health-cards" rel="noopener noreferrer"&gt;design-pattern cards&lt;/a&gt;, which also ship as a &lt;a href="https://www.figma.com/community/plugin/1268611308971699930" rel="noopener noreferrer"&gt;Figma plugin&lt;/a&gt;. Their three considerations map directly onto the app: &lt;em&gt;Preserve&lt;/em&gt; — no push notifications, no badges, no red anywhere, nothing that manufactures urgency; &lt;em&gt;Direct&lt;/em&gt; — progress you can see, and exactly one obvious next step on each screen; &lt;em&gt;Customize&lt;/em&gt; — a privacy mode you choose per call, and a mood check-in that's a scale you slide rather than a form you fill in. The cards' AI Assistants guidance — keep the person in control, make AI output fact-checkable, never let the tool override the customer — is the same discipline the reframe prompt enforces.&lt;/p&gt;

&lt;p&gt;The only server code is two stateless API routes, &lt;code&gt;/api/reframe&lt;/code&gt; and &lt;code&gt;/api/score&lt;/code&gt;, which call Gemma through a single provider layer (&lt;code&gt;src/lib/gemma.ts&lt;/code&gt;) with three paths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local&lt;/strong&gt; — Ollama serving &lt;code&gt;gemma4:e4b&lt;/code&gt; on the user's machine. The default, and the private path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hosted&lt;/strong&gt; — the same Gemma 4 weights via an OpenAI-compatible endpoint, for the Render demo. Used only when the user (or the deployment) selects it, and labelled wherever it applies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mock&lt;/strong&gt; — a clearly-labelled placeholder provider so the whole interface can be built and tested with no model present.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The prompts are contracts, not vibes. The reframe prompt forbids the model from changing any fact, softening silence into hope or hardening it into rejection, diagnosing, guessing at the reader's feelings, or adding reassurance the source text doesn't support. If the notice doesn't say something, the model must list it under "what it does not say" — never fill it in. Those rules come from an open-source skill I'd already built for exactly this problem, the &lt;a href="https://github.com/Mike-Demo/agent-skills" rel="noopener noreferrer"&gt;mental-health-support skill&lt;/a&gt;: transformations are display-only and labelled, originals are preserved, facts stay facts.&lt;/p&gt;

&lt;p&gt;The score prompt is just as strict in the other direction: score only against what the profile and the description actually state, name omissions as omissions, no flattery and no predictions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Because the most sensitive text in a job search should not have to leave your machine to be useful.&lt;/p&gt;

&lt;p&gt;An outcome notice, a private profile of what you want next, a log of how the search is going — with a closed API, every one of those has to be shipped to someone else's server before a model can help you read it. With Gemma 4 — open weights, Apache 2.0 — the model comes to the data instead. Black Box in local mode runs the whole loop on the device in front of you, costs nothing per call, works offline, and cannot change its pricing or its terms on you mid-search.&lt;/p&gt;

&lt;p&gt;I'll be precise about the limit, because it matters: the public demo can't do that. Render has no GPU, so the demo serves the same Gemma 4 weights from a hosted endpoint, and text you paste there is sent to that provider for the call. The app says so, in the interface, next to the toggle — and the toggle itself only exists because the open weights let one codebase honestly offer both paths. A closed model gives you one path and asks you not to think about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lazy Payoff
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Time for some honesty. I think mental health is something missing from the job search on both sides. The ATS systems are just trying to get through candidates as quickly as possible, while applicants are trying to apply to as many jobs as possible, both using AI to counter the other's use of AI. It's a huge arms race, and it just feels like it's not human anymore.&lt;/p&gt;

&lt;p&gt;Since I was made redundant at the end of last month, I've been really feeling this. The idea is to not initially scroll and apply to dozens of jobs a day just because it feels like you're accomplishing something. I came up with this idea after talking with my therapist, but to be honest, I haven't used it because I'm still stuck in that cycle, and it sucks. I think the people who are making these job search boards need to think about the humans on the other side of this process, because treating it as a numbers game is not working, and it's very disheartening.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Best Use of Gemma — Gemma 4 is the entire intelligence of the app: quality scoring and reframing, run locally via Ollama by default, with the same weights served hosted for the demo and disclosed as such.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Ul30e7mpMtA" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Best Use of Render — the whole app, front end and Gemma API routes, deploys as a single Render web service from the &lt;code&gt;render.yaml&lt;/code&gt; Blueprint in the repo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/xPTo79bMEbs" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Best Use of GitHub Copilot —  the whole repo went through a report-only Copilot code review before submission: every claim in this post checked against the code, every finding filed as a public draft PR, and a human decided what to do with them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/VN-w9wlMSUQ" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;🦥&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>One hub, 1,332 routes: MigrateMe Universal and the Open Migration Package</title>
      <dc:creator>Mike “Demo” Demopoulos</dc:creator>
      <pubDate>Mon, 19 Oct 2026 04:53:43 +0000</pubDate>
      <link>https://dev.to/mpmike/one-hub-1332-routes-migrateme-universal-and-the-open-migration-package-1jb7</link>
      <guid>https://dev.to/mpmike/one-hub-1332-routes-migrateme-universal-and-the-open-migration-package-1jb7</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;A few days ago I &lt;a href="https://dev.to/mpmike/open-source-migration-tool-2ki0"&gt;introduced migrateme.tech&lt;/a&gt; — an open-source, dry-run-first migration toolkit whose proof path was WordPress (WXR) → Markdown/MDX, validated on a real 44-item run. This week it grew the thing it was always pointed at: &lt;strong&gt;MigrateMe Universal&lt;/strong&gt;, an anything-to-anything content converter, and the first public release of the &lt;strong&gt;Open Migration Package (OMP)&lt;/strong&gt; — an open import/export standard designed so the converter eventually makes itself unnecessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  One hub, not N×N converters
&lt;/h3&gt;

&lt;p&gt;Every migration tool I have used is a pile of pair-to-pair converters. Add a platform and you owe a converter to and from everything else. Universal refuses that shape: every source parses into one canonical item model, and every destination renders from it. Fifteen source parsers and fifteen destination renderers — WordPress WXR, Markdown/MDX variants, Ghost, Shopify CSV, Webflow CSV, Notion and Medium exports, Sanity NDJSON, Contentful JSON, RSS/Atom, Blogger, canonical JSON, CSV, static HTML — and adding platform #38 costs one parser &lt;em&gt;or&lt;/em&gt; one renderer, never both.&lt;/p&gt;

&lt;h3&gt;
  
  
  A registry that tells the truth
&lt;/h3&gt;

&lt;p&gt;The converter's registry covers 37 nodes: 21 researched platforms (10 AI builders — Replit, Lovable, Bolt.new, v0, Bubble, Softr, Glide, AppSheet, Adalo, DronaHQ — and 11 CMS platforms by market share, WordPress at the top) plus the format connectors. That is 37 × 36 = &lt;strong&gt;1,332 directed pairs&lt;/strong&gt;, and every pair has its own landing page stating plainly whether the route is &lt;strong&gt;Supported&lt;/strong&gt;, &lt;strong&gt;Lossy&lt;/strong&gt; — with the losses named, not footnoted — or &lt;strong&gt;Planned&lt;/strong&gt;. Every pair also has its own canonical address: &lt;a href="https://lovable.wordpress.migrateme.tech/" rel="noopener noreferrer"&gt;lovable.wordpress.migrateme.tech&lt;/a&gt; is the Lovable → WordPress route (the path form, universal.migrateme.tech/convert/lovable-to-wordpress, redirects there — no duplicate URLs). The whole index is public, too: &lt;a href="https://migrateme.tech/sitemap-pairs.xml" rel="noopener noreferrer"&gt;sitemap-pairs.xml&lt;/a&gt; lists all 1,332 canonical pair URLs.&lt;/p&gt;

&lt;p&gt;Honesty is a feature here, and it cuts both ways: when a source platform offers no export at all, the built-in &lt;strong&gt;Scanner (lite)&lt;/strong&gt; discovers what it can from sitemaps, feeds, and structured data — in the browser, respecting robots rules, never pretending to be a full crawler and never going near a login wall.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The pair wheel — all 1,332 addresses in 29 seconds.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/T3ZcVmvvfcc" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  The Open Migration Package
&lt;/h3&gt;

&lt;p&gt;The converter is the reference implementation; the standard is the point. An OMP package is a &lt;code&gt;manifest.json&lt;/code&gt; (source, items, assets, taxonomy, mappings, provenance, sha256 checksums over every file), a &lt;code&gt;content/&lt;/code&gt; folder of Markdown/MDX with Portable Text bodies, and an &lt;code&gt;assets/&lt;/code&gt; index. There is a published JSON Schema, a validator that returns specific errors instead of vibes, and conformance levels — OMP Reader, OMP Writer, OMP Full — so a platform can adopt incrementally. The ask to every builder and CMS on the registry: implement two translators (to-OMP, from-OMP) instead of N×M converters, and your users can leave whenever they want. That is what an exit door looks like.&lt;/p&gt;

&lt;p&gt;The spec lives in the repo at &lt;code&gt;docs/format/open-migration-package.md&lt;/code&gt;, the schema and validator in &lt;code&gt;packages/format&lt;/code&gt;, and this weekend Universal folded into the main monorepo — &lt;code&gt;packages/connectors/universal&lt;/code&gt; for the parsers and renderers, &lt;code&gt;apps/web/universal&lt;/code&gt; for the app, and Manifest v2 in &lt;code&gt;packages/core&lt;/code&gt;, which generalises the original v1 manifest while keeping every v1 file valid.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Building a new standard — the Open Migration Package in 74 seconds.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/dgiR0blLYKs" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Who it's for, and who would pay
&lt;/h3&gt;

&lt;p&gt;The user is anyone whose content is fenced in: a freelancer whose client's site lives on a builder they want to leave, a small agency doing the same migration for the tenth client by hand, a hobbyist community moving off a platform that's shutting down. Migrations are episodic, high-stakes, and currently priced like hostage negotiations — agency line items and per-site SaaS fees for what is, mechanically, a format conversion with a risk report.&lt;/p&gt;

&lt;p&gt;The toolkit itself is free and MIT-licensed, and the AI step runs a local open-weight model, so a migration costs nothing to run — that's what makes freemium honest here rather than a trial in disguise. The business model it grows into is a &lt;strong&gt;Commons Donation Bundle&lt;/strong&gt;: when a migration succeeds, the tool inventories the open-source technology it touched — the platform the site came from, the platform it's going to, and the stack the tool itself stands on — and assembles a suggested donation across all three, Humble Bundle–style, with a slider for the amount and the split. Designed, not yet wired: no payments are taken today. A tool that moves people between open-source platforms should feed the commons it depends on.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How the monetization works — the Commons Donation Bundle.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Ja2zHIB689E" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/_xQT_cHWt30" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it live:&lt;/strong&gt; &lt;a href="https://universal.migrateme.tech/" rel="noopener noreferrer"&gt;https://universal.migrateme.tech/&lt;/a&gt; — it runs entirely in your browser; nothing you upload leaves your device. Every route is live too, e.g. &lt;a href="https://wordpress.markdown.migrateme.tech/" rel="noopener noreferrer"&gt;wordpress.markdown.migrateme.tech&lt;/a&gt; for the flagship route, or &lt;a href="https://lovable.wordpress.migrateme.tech/" rel="noopener noreferrer"&gt;lovable.wordpress.migrateme.tech&lt;/a&gt; for a Lossy one with its losses named. Project home: &lt;a href="https://migrateme.tech/" rel="noopener noreferrer"&gt;https://migrateme.tech/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/7V8OzZEk8XQ" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Mike-Demo" rel="noopener noreferrer"&gt;
        Mike-Demo
      &lt;/a&gt; / &lt;a href="https://github.com/Mike-Demo/migrateme.tech" rel="noopener noreferrer"&gt;
        migrateme.tech
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Open-source AI-assisted CMS migration toolkit. Dry-run-first, local-first WordPress → Markdown migrations via CLI, MCP, web, and agents. 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;migrateme.tech&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Open-source AI-assisted CMS migration toolkit. Dry-run-first, local-first WordPress → Markdown migrations via CLI, MCP, web, and agents.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;MigrateMe Universal + Open Migration Package (folded in 2026-10-18)&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The anything-to-anything Universal converter and the Open Migration
Package (OMP) standard (issue #34) were folded in from the Universal
Bolt Forge build:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;packages/connectors/universal&lt;/code&gt; — 15 source parsers + 15 destination
renderers on one canonical hub (no pair-to-pair converters), plus the
21-platform registry with honest Supported / Lossy / Planned labels.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;packages/format&lt;/code&gt; (&lt;code&gt;@migrateme/format&lt;/code&gt;) — the OMP manifest JSON Schema
and validator surface; the spec lives at
&lt;code&gt;docs/format/open-migration-package.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;packages/core&lt;/code&gt; gained Manifest v2 (&lt;code&gt;manifest-v2.ts&lt;/code&gt;): v1 manifests
upgrade losslessly, so any registered pair can be described.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apps/web/universal&lt;/code&gt; — the Universal web app (standalone Vite app
live at &lt;a href="https://universal.migrateme.tech" rel="nofollow noopener noreferrer"&gt;https://universal.migrateme.tech&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Setup&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Use Node.js &lt;strong&gt;24.21.0&lt;/strong&gt; (version in &lt;code&gt;.nvmrc&lt;/code&gt;) and pnpm &lt;strong&gt;10.22.0&lt;/strong&gt; (pinned by
&lt;code&gt;packageManager&lt;/code&gt; in the root &lt;code&gt;package.json&lt;/code&gt;). Enable Corepack and install…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Mike-Demo/migrateme.tech" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;packages/connectors/universal&lt;/code&gt; — the source parsers and destination renderers (the hub's spokes)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;packages/format&lt;/code&gt; — the OMP package reader/writer, JSON Schema, and validator&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;packages/core&lt;/code&gt; — Manifest v2, the canonical model everything parses into&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apps/web/universal&lt;/code&gt; — the browser app: matrix, pair pages, converter, Scanner (lite)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/format/open-migration-package.md&lt;/code&gt; — the OMP spec; &lt;code&gt;docs/copilot-usage.md&lt;/code&gt; — the running log of how the AI builders and reviewers were used, and checked&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Universal was built during a Bolt Forge weekend on &lt;strong&gt;GLM 5.3 Flash, an open-weight model&lt;/strong&gt;, driven in narrow single-purpose prompts — big prompts died on the run budget, so the work was sliced until each prompt did exactly one thing. The open model is not decoration: it wrote the parsers, the renderers, the pair-page generator, and the app shell.&lt;/p&gt;

&lt;p&gt;Around it, a strict rule: &lt;strong&gt;nothing counts as done until it is verified in the synced GitHub code and the live output&lt;/strong&gt; — AI builders' completion claims included. Every build round went through &lt;strong&gt;GitHub Copilot&lt;/strong&gt; as an adversarial reviewer, not a rubber stamp: it caught a data-loss bug in the OMP asset packaging and an injection hole in WXR parsing before either shipped, and the fold-in PR carried 13 review findings — 12 fixed, one answered as a design point. Accessibility was a from-the-first-prompt requirement, not an audit-week patch: WCAG 2.2 AA targets, keyboard-first flows, aria-live progress, and statuses that are always icon &lt;strong&gt;plus&lt;/strong&gt; text, never colour alone. The whole site family also moved hosting this weekend — migrateme.tech, the converter, and the run-output site now all serve from SpaceFast.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How Copilot was used — and checked — across the whole build.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/xI3q7nLlUFQ" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Because the problem this tool solves &lt;em&gt;is&lt;/em&gt; closed-ness. Platforms fence content in with proprietary exports precisely because exit is supposed to hurt. A closed migration API would reproduce the disease: your escape hatch, rented back to you, revocable at pricing-page notice.&lt;/p&gt;

&lt;p&gt;Open pieces are what make Universal work, specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The standard is open.&lt;/strong&gt; OMP is MIT-licensed with a published schema, so a platform adopting it isn't integrating with my product — it's implementing a format its users can verify. I've already opened an interop conversation with Automattic's liberate.sh team, offering an OMP writer and shared testing, in a public issue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The model is open-weight.&lt;/strong&gt; GLM 5.3 Flash ran the build at no per-token cost during the Forge weekend, and the toolkit's own AI step is designed to run a local open-weight model — a migration costs nothing to run, which is what makes the free tier honest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The execution is local.&lt;/strong&gt; Conversions run in the visitor's browser. There is no server for your content to leak from, no upload to trust anyone with. A closed cloud converter couldn't make that promise structurally — only contractually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The work is inspectable.&lt;/strong&gt; Every claim in this post — the 44-item validated run, the review findings, the pair counts — resolves to a public commit, issue, or page. Open innovation is also an audit trail.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you build a platform: the standard is MIT-licensed, the schema is published, and the reference implementation is right there. Give your users an exit door.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;No DevRelay session for this one — the build's agent work happened in the open on GitHub instead. The sessions are the issue and PR threads: the Universal build was commissioned and tracked in issues (design restyle: #38, homepage: #41), Copilot's review reports live on the PRs (fold-in: #35; the full review report: #37), and &lt;code&gt;docs/copilot-usage.md&lt;/code&gt; in the repo is the running session log — prompts, verdicts, and the bugs the reviewers caught, in order.&lt;/p&gt;

&lt;h2&gt;
  
  
  My First User
&lt;/h2&gt;

&lt;p&gt;Yes — an agency PM I know took an early version for a spin last week, and their feedback steered what v2 became: less "a better WordPress exporter," more "the hub has to be the product." They didn't pay — the tool is free, and the donation bundle isn't wired yet — but a working practitioner telling you your scope is wrong, early enough to fix it, is worth more than a first dollar at this stage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Best Use of GitHub Copilot&lt;/li&gt;
&lt;li&gt;Best Use of a .tech Domain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What's next:&lt;/strong&gt; more parsers and renderers down the registry's Planned list (issue #32) · a server/CLI full crawler to sit behind Scanner (lite)'s honesty boundary · OMP adoption outreach to the registry platforms, AI builders first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Videos
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;What's next for MigrateMe — the roadmap.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/UP7Dxe-Wlzg" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;DXS: the Digital Experience Showcase test bed — real sandboxes, real proof runs.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/cgET88eHKDQ" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>opensource</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Every Game Is Connected — I Built the Graph That Proves It</title>
      <dc:creator>Mike “Demo” Demopoulos</dc:creator>
      <pubDate>Sat, 17 Oct 2026 20:01:18 +0000</pubDate>
      <link>https://dev.to/mpmike/every-game-is-connected-i-built-the-graph-that-proves-it-524i</link>
      <guid>https://dev.to/mpmike/every-game-is-connected-i-built-the-graph-that-proves-it-524i</guid>
      <description>&lt;h2&gt;
  
  
  Every Game Is Connected — I Built the Graph That Proves It
&lt;/h2&gt;

&lt;p&gt;Recommendation engines are great at telling you &lt;em&gt;what&lt;/em&gt; is similar to the game you just played. They are terrible at telling you &lt;em&gt;why&lt;/em&gt; two games are connected — especially when the connection runs across studios, decades, and genres.&lt;/p&gt;

&lt;p&gt;That "why" bothered me, because it isn't really a fact about either game. Elden Ring and Stardew Valley share almost nothing you'd put in a database row. But there are real paths between them — through other games, through the people and companies who made them, through lineages of remakes and expansions. The connection is a property of the &lt;em&gt;paths&lt;/em&gt;, and paths are what graphs are for.&lt;/p&gt;

&lt;p&gt;So for Graph Hacks (WeMakeDevs × FalkorDB), I built the &lt;strong&gt;Gaming Multiverse Reasoner&lt;/strong&gt;: pick any 2–4 games, and it traverses a FalkorDB graph of &lt;strong&gt;50,217 games, 84,296 nodes, and 1,023,292 relationships&lt;/strong&gt; to find the hidden paths between them — then an AI narrates the result, with every claim verifiable by clicking it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Try it live:&lt;/strong&gt; &lt;a href="https://multiverse.2fy1rnikhcll.us-south.codeengine.appdomain.cloud" rel="noopener noreferrer"&gt;https://multiverse.2fy1rnikhcll.us-south.codeengine.appdomain.cloud&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/Mike-Demo/gaming-multiverse-reasoner" rel="noopener noreferrer"&gt;https://github.com/Mike-Demo/gaming-multiverse-reasoner&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Demo video (2:55):&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/OfkZN_ELiIA" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhuha7z7ohd5xibqojhqy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhuha7z7ohd5xibqojhqy.gif" alt="The four-game query running live" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Ask about Elden Ring, Hades, Stardew Valley, and Baldur's Gate III and you get &lt;strong&gt;24 paths in about 2 seconds&lt;/strong&gt;. Five kinds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Direct lineage&lt;/strong&gt; — remakes, remasters, DLC, expansions, versions, shared collection/franchise parents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Company bridges&lt;/strong&gt; — a studio or publisher whose &lt;em&gt;other&lt;/em&gt; games join the pair&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Similar-game chains&lt;/strong&gt; — shortest paths over IGDB's similarity graph&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Common neighbours&lt;/strong&gt; — games IGDB lists as similar to both&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared threads&lt;/strong&gt; — a genre, theme, or engine both games genuinely share&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click any path card — or any sentence of the narration, or any node in the graph — and that exact path lights up. There's also a "Surprise me" slot machine that picks four random games, because a system tuned to one lucky demo set is a magic trick, not a product.&lt;/p&gt;

&lt;p&gt;The core Cypher is almost disappointingly small. Similar-game chains are one &lt;code&gt;shortestPath&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cypher"&gt;&lt;code&gt;&lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;a:&lt;/span&gt;&lt;span class="n"&gt;Game&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;igdb_id:&lt;/span&gt;&lt;span class="n"&gt;$a&lt;/span&gt;&lt;span class="ss"&gt;}),&lt;/span&gt; &lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;b:&lt;/span&gt;&lt;span class="n"&gt;Game&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;igdb_id:&lt;/span&gt;&lt;span class="n"&gt;$b&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="nf"&gt;shortestPath&lt;/span&gt;&lt;span class="ss"&gt;((&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:SIMILAR_TO&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;..4&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="ss"&gt;))&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
&lt;span class="k"&gt;UNWIND&lt;/span&gt; &lt;span class="nf"&gt;nodes&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;n.igdb_id&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n.name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every path card in the UI shows the actual query that produced it. If the graph did the work, you should be able to see the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning 1: Your biggest nodes are lying to you
&lt;/h2&gt;

&lt;p&gt;The first version of this gave worthless answers, and the reason was hubs. Nearly every game in the catalogue is on "PC," and a huge share of them are tagged "Adventure." Route paths through those nodes and &lt;em&gt;everything&lt;/em&gt; connects to &lt;em&gt;everything&lt;/em&gt; in two hops — technically true, completely meaningless.&lt;/p&gt;

&lt;p&gt;So the Reasoner suppresses hubs, mechanically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Platforms and game modes &lt;strong&gt;never&lt;/strong&gt; appear in paths&lt;/li&gt;
&lt;li&gt;Any genre, theme, or engine shared by more than &lt;strong&gt;12,000 games&lt;/strong&gt; is suppressed ("Indie" and "Adventure" fail this test; "RPG" and "Fantasy" pass it)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rule is printed in the app header. I think that's the important part: a suppression rule you hide is cherry-picking; a suppression rule you publish is a methodology.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning 2: A silent limit will quietly poison your results
&lt;/h2&gt;

&lt;p&gt;Mid-build, I computed game communities — clusters from weighted label propagation over the similarity graph — and the numbers looked off. They were. FalkorDB caps any result set at 10,000 rows, and it does so &lt;strong&gt;silently&lt;/strong&gt;. My first community computation ran on a truncated projection of the graph and I only caught it by counting rows by hand. (My first fix then collapsed the whole graph into one 27,403-member monster community, which is its own lesson: unweighted label propagation over a dense similarity graph needs weights and a size cap. The shipped version weights mutual links ×2, caps communities at 1,500 members, and found 6,234 communities — Elden Ring lands in an 8-game soulslike cluster, which feels right.)&lt;/p&gt;

&lt;p&gt;The fix for the cap was paging the projection by ID ranges. The lesson I'm keeping: &lt;strong&gt;verify counts against an independent total before you build anything on a query result.&lt;/strong&gt; A limit that doesn't announce itself isn't a bug exactly, but it is a trap — and it's the first piece of feedback I'd hand the FalkorDB team, along with two smaller things: typed-union relationship patterns (&lt;code&gt;[r:T1|T2|…]&lt;/code&gt;) were surprisingly slow on our graph, and the ACL ergonomics around &lt;code&gt;SETUSER&lt;/code&gt; could use clearer error messages. None of it stopped the build, and the parts that matter — traversal speed, &lt;code&gt;shortestPath&lt;/code&gt;, read-only &lt;code&gt;GRAPH.RO_QUERY&lt;/code&gt; with ACL users for a public demo — were genuinely good.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning 3: Don't make the AI trustworthy — make it checkable
&lt;/h2&gt;

&lt;p&gt;The narration is IBM watsonx (Granite), and it has exactly one job: explain paths the graph already found. It never picks games, never writes queries, never invents facts. It returns claims as structured JSON, and here's the part I care about: &lt;strong&gt;every claim must cite the IDs of the paths it describes.&lt;/strong&gt; Code validates each citation against the paths FalkorDB actually returned. A claim that cites nothing real is dropped before you ever see it.&lt;/p&gt;

&lt;p&gt;And because claims carry path IDs, clicking a claim highlights the path in the graph. The AI doesn't ask you to trust it — it hands you the receipt. If watsonx is down, the app falls back to template explanations built from the same paths and labels them &lt;code&gt;template&lt;/code&gt;, because the badge should always say which source you're reading.&lt;/p&gt;

&lt;p&gt;Same honesty rule everywhere else: search results are never cached (the millisecond readout in the UI is the server's own measurement for that run — I like watching it), communities are precomputed and &lt;em&gt;labeled&lt;/em&gt; precomputed, and &lt;code&gt;SIMILAR_TO&lt;/code&gt; edges are IGDB's own data, credited as such. I refused to add invented "inspired by" edges even though they'd have looked great in the demo. An invented edge would have poisoned the whole grounding story.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rest of the stack, briefly
&lt;/h2&gt;

&lt;p&gt;FalkorDB runs in Docker on a single IBM VPC virtual server (bx2-4x16, us-south). The app is a &lt;strong&gt;single-file Python 3.12 program using only the standard library — zero third-party packages&lt;/strong&gt; — speaking RESP to FalkorDB directly, hosted on IBM Code Engine with min-scale 1 so the demo URL is never cold. The IGDB snapshot (frozen 14 Oct 2026) sits in Cloud Object Storage; the catalogue started as IGDB's entire rated population and grew through critic-only, hyped, newest, and similarity-frontier tiers, plus the full QueerCade catalogue merged in.&lt;/p&gt;

&lt;p&gt;The app is also an agent surface, because the track is &lt;em&gt;Agents That Act on Connected Data&lt;/em&gt;: it hosts an MCP server with five tools (&lt;code&gt;resolve_game&lt;/code&gt;, &lt;code&gt;find_paths&lt;/code&gt;, &lt;code&gt;random_games&lt;/code&gt;, &lt;code&gt;game_community&lt;/code&gt;, &lt;code&gt;narrate&lt;/code&gt;), so other agents can reason over the same graph. It scored 18/30 on a Silicon Friendly agent-readiness audit and 100/100 on a Lighthouse accessibility audit — both reports are public in the repo, fails included.&lt;/p&gt;

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

&lt;p&gt;Bring your own four games — ideally four you think have &lt;em&gt;nothing&lt;/em&gt; to do with each other. Those are the fun ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://multiverse.2fy1rnikhcll.us-south.codeengine.appdomain.cloud" rel="noopener noreferrer"&gt;https://multiverse.2fy1rnikhcll.us-south.codeengine.appdomain.cloud&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built solo by Mike "Demo" Demopoulos for Graph Hacks 2026 (Track 1 — Agents That Act on Connected Data). Project code is MIT licensed. &lt;em&gt;Disclosure: the application code was written with an AI coding agent under my direction, with every subsystem verified live; narration at runtime is IBM watsonx; the demo video was produced with Pexo from real captures of the live app. Game data is IGDB's; this is a fan/hackathon project, not affiliated with IGDB or any publisher.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>falkordb</category>
      <category>hackathon</category>
      <category>ai</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Open Source Migration Tool</title>
      <dc:creator>Mike “Demo” Demopoulos</dc:creator>
      <pubDate>Wed, 14 Oct 2026 22:10:30 +0000</pubDate>
      <link>https://dev.to/mpmike/open-source-migration-tool-2ki0</link>
      <guid>https://dev.to/mpmike/open-source-migration-tool-2ki0</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F87z9x2cx6r0pawkosg0v.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F87z9x2cx6r0pawkosg0v.gif" alt="The checkpoint: the plan is reviewed and approved before anything moves" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every WordPress freelancer I know has a migration story, and none of them are happy. A client wants off their old host, or off WordPress entirely, and somebody has to move ten years of posts, pages, taxonomies, comments, and media into a new system without losing anything. The tooling is export buttons, importer plugins, and hope. The work is billable, dreaded, and one bad run away from a very long weekend.&lt;/p&gt;

&lt;p&gt;So I built the tool I watched people need for a decade in the hosting industry: &lt;strong&gt;migrateme.tech&lt;/strong&gt;, an open-source, AI-assisted CMS migration toolkit whose defining feature is restraint. It is not a WordPress exit tool. It is a route between any two platforms, in either direction — and WordPress to Markdown is simply the first route that shipped, chosen because WXR is an open, documented export format and the pain is the one I know best. The engine is built around a canonical manifest: connectors turn a source into the manifest, mappers work on the manifest, destinations render from it. Add a connector and a destination and the route exists — Lovable to WordPress, Joomla to WordPress, WordPress to Drupal, a closed SaaS export to an open one. WordPress appears on both sides of those examples on purpose: it is a source here and a destination on the roadmap, because the goal was never leaving a platform. It is being able to move.&lt;/p&gt;

&lt;p&gt;The first route migrates WordPress (via a standard WXR export) to Markdown/MDX. But before it writes a single file, it does three things most migration tools skip:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It shows its work.&lt;/strong&gt; A dry run reads the export, builds a canonical manifest of everything in it, maps every field, renders the output in memory, and writes &lt;em&gt;nothing&lt;/em&gt;. You get a risk report instead: unresolved field mappings, unsupported fields, missing assets, validation concerns. The zero-writes property isn't a promise — it's covered by tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It asks permission.&lt;/strong&gt; Every surface fails closed. The CLI's &lt;code&gt;migrate&lt;/code&gt; command refuses to run without &lt;code&gt;--approve&lt;/code&gt;. The MCP server's &lt;code&gt;execute_migration&lt;/code&gt; tool refuses unless the caller passes &lt;code&gt;approved: true&lt;/code&gt;. The web flow returns HTTP 400 if you POST without the approval control. An unapproved run writes nothing and persists no state — also tested, on all three surfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It plans for the crash.&lt;/strong&gt; Approved runs are checkpointed to on-disk state. Kill one halfway, restart it, and it resumes where it stopped and produces output identical to an uninterrupted run. Reruns skip completed items. Afterward, a validation engine reconciles counts, fields, assets, and checksums between source and destination, and anything it can't reconcile lands in an explicit exception queue instead of a shrug.&lt;/p&gt;

&lt;p&gt;Field mapping is &lt;strong&gt;deterministic first, AI second&lt;/strong&gt;. A rule-based mapper handles everything it can prove. Only the leftovers go to the AI mapper, which runs a local open-weight model through Ollama and may only propose targets from the destination's actual field list — its output is validated against a strict schema before it's accepted. Malformed output, an invented field, a prompt-injection attempt buried in post content, or the model simply being down: all of it falls back to a manual-review queue. The AI can suggest. It cannot invent, and it cannot write.&lt;/p&gt;

&lt;p&gt;One engine, every route, three ways to drive it: a &lt;strong&gt;CLI&lt;/strong&gt; (&lt;code&gt;plan&lt;/code&gt;, &lt;code&gt;dry-run&lt;/code&gt;, &lt;code&gt;migrate&lt;/code&gt;, &lt;code&gt;validate&lt;/code&gt;, &lt;code&gt;job&lt;/code&gt;), an &lt;strong&gt;MCP server&lt;/strong&gt; with six tools so other agents can run migrations under the same approval rules, and a &lt;strong&gt;web flow&lt;/strong&gt; (upload → inventory → mapping review → dry-run preview → approval → migrate → validation report) that contains no business logic of its own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who pays for this?&lt;/strong&gt; Nobody has to — and that's the business model. The toolkit is freemium in the literal sense: free, MIT-licensed, and cheap to run because the AI step is a local model with zero marginal cost. The people who'll reach for it first are the ones who already get paid to migrate sites — freelancers, small agencies, consultants moving clients between platforms in either direction — because the risk in a migration is concentrated in exactly the steps this tool makes visible: what will break, what won't map, what went missing. A dry run with a risk report is something you can attach to a quote; a validation report is proof of work you can hand a client.&lt;/p&gt;

&lt;p&gt;The revenue idea is a &lt;strong&gt;donation bundle, Humble Bundle style&lt;/strong&gt;. When a migration succeeds, the tool inventories the open-source technology it touched — the platform the site came from, the platform it's going to, and the open-source stack the tool itself stands on — and where a project has an open-source foundation behind it, it assembles a suggested donation across all three directions. A set of sliders lets the user choose the total and the split: how much supports this tool, and how much flows back to the foundations and libraries that made the original site, the conversion, and the new site possible. A tool that moves people between open-source platforms should feed the commons it depends on. The bundle is designed, not yet wired — the landing page carries a working concept demo of the sliders.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foolytkk4vdzvavzy3c1l.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foolytkk4vdzvavzy3c1l.gif" alt="You set the total, then drag the sliders to split it — the total never changes" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/qv01E37DFZI" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9aoyb3e62r51spxnbuui.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9aoyb3e62r51spxnbuui.gif" alt="Every address declares what it is, before you click it" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live site:&lt;/strong&gt; &lt;a href="https://migrateme.tech" rel="noopener noreferrer"&gt;migrateme.tech&lt;/a&gt; — the project home, served from the repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web flow:&lt;/strong&gt; runs from the repo today (&lt;code&gt;apps/web&lt;/code&gt;); clone, &lt;code&gt;pnpm install&lt;/code&gt;, and drive a sample export through upload → approval → validation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test beds, live:&lt;/strong&gt; the toolkit is exercised against purpose-built sites, not toy data. Read the addresses first — they follow the project's naming convention, so each link declares what it is before you click it: the platform, the route it took, and where the output lives.

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://lovable.sandbox.migrateme.tech" rel="noopener noreferrer"&gt;lovable.sandbox.migrateme.tech&lt;/a&gt; and &lt;a href="https://lovable.cloud.sandbox.migrateme.tech" rel="noopener noreferrer"&gt;lovable.cloud.sandbox.migrateme.tech&lt;/a&gt; — DXS, a CMS test bed with 22 content models and 23 route patterns, in non-cloud and Supabase variants.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://wp.sandbox.migrateme.tech" rel="noopener noreferrer"&gt;wp.sandbox.migrateme.tech&lt;/a&gt; — a real WordPress.com site seeded specifically to produce a messy, honest WXR export (more on that below).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://wp.spacefast.sandbox.migrateme.tech" rel="noopener noreferrer"&gt;wp.spacefast.sandbox.migrateme.tech&lt;/a&gt; — the same WordPress test bed, published to SpaceFast as a static mirror via the SpaceFast CLI — the official WordPress plugin's publish stalled three times on WordPress.com, so this edition took the side door (bug reported to SpaceFast). The commercial-platform baseline to compare this toolkit's dry-run-first output against.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://from.wp.sandbox.migrateme.tech" rel="noopener noreferrer"&gt;from.wp.sandbox.migrateme.tech&lt;/a&gt; — the output of this toolkit's own run against that WordPress site, published as a static site: every migrated item rendered, the raw engine output beside it, and the full manifest.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Mike-Demo" rel="noopener noreferrer"&gt;
        Mike-Demo
      &lt;/a&gt; / &lt;a href="https://github.com/Mike-Demo/migrateme-from-wp-sandbox" rel="noopener noreferrer"&gt;
        migrateme-from-wp-sandbox
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Published output of the migrateme.tech toolkit's first real-world run — from wp.sandbox.migrateme.tech (WXR) to Markdown, Oct 14 2026.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;from.wp.sandbox.migrateme.tech&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;The published output of the &lt;a href="https://github.com/Mike-Demo/migrateme.tech" rel="noopener noreferrer"&gt;migrateme.tech&lt;/a&gt; toolkit's first real-world run.&lt;/p&gt;
&lt;p&gt;Source: the live WordPress testbed at &lt;a href="https://wp.sandbox.migrateme.tech" rel="nofollow noopener noreferrer"&gt;wp.sandbox.migrateme.tech&lt;/a&gt; (DXS — Digital Experience Showcase).
Its WXR export (44 items) was migrated on October 14, 2026 — plan → dry run → approved migration → validation (44/44, empty exception queue).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;index.html&lt;/code&gt; + &lt;code&gt;items/&lt;/code&gt; — the run, rendered as a static site (generated by &lt;code&gt;generate.py&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;raw/&lt;/code&gt; — the exact Markdown files the engine wrote, byte for byte&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;manifest.json&lt;/code&gt; — the full run manifest: 420 field mappings, provenance, checksums&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;MIT licensed. Built by Mike "Demo" Demopoulos.&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Mike-Demo/migrateme-from-wp-sandbox" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  The addresses are part of the demo
&lt;/h3&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/LNV4KZDbTRI" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The domain isn't a label; it's the routing table. The post-MVP vision (issue #17) gives every supported migration pair its own address in the form &lt;em&gt;source.to.destination&lt;/em&gt; — &lt;code&gt;lovable.to.wordpress.migrateme.tech&lt;/code&gt; reads as the route it serves, and &lt;code&gt;wordpress.to.static.migrateme.tech&lt;/code&gt; names the WordPress-to-static route the SpaceFast edition below already proves by hand. The sandbox namespace is already live on the domain (&lt;code&gt;lovable.sandbox&lt;/code&gt;, &lt;code&gt;lovable.cloud.sandbox&lt;/code&gt;, &lt;code&gt;wp.sandbox&lt;/code&gt;, and now &lt;code&gt;wp.spacefast.sandbox&lt;/code&gt; for the SpaceFast-hosted edition) — labels stacked like words in a sentence, each address declaring what it is. As the connector roadmap (issue #32) adds sources and destinations in both directions — Ghost, Contentful, Sanity, Drupal, WordPress as a &lt;em&gt;destination&lt;/em&gt; — each new route gets a name that's also its address. The roadmap already names them on both sides of the arrow: Lovable, Joomla, Drupal, and Ghost as sources &lt;em&gt;and&lt;/em&gt; destinations, the closed SaaS builders and hosted CMSs whose exports trap people today, and WordPress as a destination, not just a way out. One disclosure, since a prize category turns on it: I missed the free-domain promo entirely and bought migrateme.tech through my existing registrar during the challenge window — claimed for this project, just not through the promo.&lt;/p&gt;

&lt;p&gt;Quick start:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;corepack &lt;span class="nb"&gt;enable
&lt;/span&gt;pnpm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--frozen-lockfile&lt;/span&gt;
pnpm build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pnpm typecheck &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pnpm &lt;span class="nb"&gt;test&lt;/span&gt;   &lt;span class="c"&gt;# 41 tests&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5b9mc0rmqro0q4qg5xwl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5b9mc0rmqro0q4qg5xwl.gif" alt="Fifteen issues, planned as one dependency graph" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Mike-Demo" rel="noopener noreferrer"&gt;
        Mike-Demo
      &lt;/a&gt; / &lt;a href="https://github.com/Mike-Demo/migrateme.tech" rel="noopener noreferrer"&gt;
        migrateme.tech
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Open-source AI-assisted CMS migration toolkit. Dry-run-first, local-first WordPress → Markdown migrations via CLI, MCP, web, and agents. 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;migrateme.tech&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Open-source AI-assisted CMS migration toolkit. Dry-run-first, local-first WordPress → Markdown migrations via CLI, MCP, web, and agents.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Setup&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Use Node.js &lt;strong&gt;24.21.0&lt;/strong&gt; (version in &lt;code&gt;.nvmrc&lt;/code&gt;) and pnpm &lt;strong&gt;10.22.0&lt;/strong&gt; (pinned by
&lt;code&gt;packageManager&lt;/code&gt; in the root &lt;code&gt;package.json&lt;/code&gt;). Enable Corepack and install from
the repository root:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;corepack &lt;span class="pl-c1"&gt;enable&lt;/span&gt;
pnpm install --frozen-lockfile&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Build, type-check, and run the test suite with:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;pnpm build
pnpm typecheck
pnpm &lt;span class="pl-c1"&gt;test&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Test bed — DXS (Digital Experience Showcase)&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;migrateme is exercised against &lt;strong&gt;DXS&lt;/strong&gt;, a purpose-built CMS/SaaS migration
test bed with rich content models, stable fixture identifiers, and a full
component library — so migrations can be verified end to end (record counts,
field values, reference integrity, publication state, ordering, asset
metadata, and rich-text rendering) instead of eyeballed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Canonical brief &amp;amp; content contracts: &lt;a href="https://github.com/Mike-Demo/dxs-cms-testbed" rel="noopener noreferrer"&gt;Mike-Demo/dxs-cms-testbed&lt;/a&gt; — based on a prompt from Microsoft Copilot Cowork&lt;/li&gt;
&lt;li&gt;Non-cloud (mock data layer) implementation: &lt;a href="https://github.com/Mike-Demo/dxs-non-cloud" rel="noopener noreferrer"&gt;Mike-Demo/dxs-non-cloud&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cloud (Supabase data layer) implementation: &lt;a href="https://github.com/Mike-Demo/info-grove" rel="noopener noreferrer"&gt;Mike-Demo/info-grove&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live deployments…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Mike-Demo/migrateme.tech" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;MIT-licensed TypeScript monorepo. The architecture is one decision, repeated: &lt;strong&gt;a canonical manifest is the contract.&lt;/strong&gt; Connectors extract a source into the manifest (strict Zod schemas — unknown fields are rejected, not silently dropped). Mappers work on the manifest. Destinations render from it. The CLI, MCP server, and web app are thin shells over the same core, which is why the approval gate can't be bypassed by picking a different door.&lt;/p&gt;

&lt;p&gt;The test-bed repos are part of the project, not decoration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Mike-Demo/dxs-cms-testbed" rel="noopener noreferrer"&gt;dxs-cms-testbed&lt;/a&gt; — the canonical DXS brief and content contracts. Provenance matters, so it's stated in the repo too: the brief is based on a prompt from &lt;strong&gt;Microsoft Copilot Cowork&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Mike-Demo/dxs-non-cloud" rel="noopener noreferrer"&gt;dxs-non-cloud&lt;/a&gt; and &lt;a href="https://github.com/Mike-Demo/info-grove" rel="noopener noreferrer"&gt;info-grove&lt;/a&gt; — the two DXS implementations the connectors will be built against.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The roadmap around them is connector-shaped, because the architecture is: issue #32 sequences the connector program — Lovable first as a source, then the rest in both directions, including the closed SaaS platforms people are most often locked into — and issue #34 proposes an Open Migration Package format (portable content bodies, integrity manifests) plus a connector-authoring kit, so a route nobody has built yet is a connector away, not a rewrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Favt7azd5o9ajtq9ofh67.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Favt7azd5o9ajtq9ofh67.gif" alt="Nothing merged on trust: install, build, typecheck, tests — then merge" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The open-source AI at the core
&lt;/h3&gt;

&lt;p&gt;The AI in this project is open, local, and deliberately weak where it matters. The field mapper's second pass runs an &lt;strong&gt;open-weight model served by Ollama&lt;/strong&gt; on the user's own machine — no API key, no hosted inference, no client content leaving the laptop. The model is swappable by configuration because the mapper doesn't trust it anyway: it may only propose targets from the destination's real field list, its output is validated against a strict schema, and every failure mode — malformed output, invented field, provider down — routes to a human review queue instead of a write. Around it, the harness is open too: the &lt;strong&gt;Model Context Protocol&lt;/strong&gt; (an open standard) is one of the three surfaces, so other agents can drive migrations under the same approval rules a human gets. The project is built around the constraint that open AI makes possible: inference cheap and private enough to put inside a free tool, and inspectable enough to verify like code.&lt;/p&gt;

&lt;h3&gt;
  
  
  The build
&lt;/h3&gt;

&lt;p&gt;The engine was built in &lt;strong&gt;one day&lt;/strong&gt; (October 13), as fifteen GitHub issues in a strict dependency chain — manifest before mappers, mappers before pipelines, pipelines before surfaces — with &lt;strong&gt;GitHub Copilot's coding agent&lt;/strong&gt; writing the code, issue by issue, and a second agent (Cane, the assistant orchestrating this project) verifying every pull request before merge. I directed: scope, sequencing, acceptance criteria, and every public-facing decision.&lt;/p&gt;

&lt;p&gt;The verification discipline exists because of what happened first. Copilot's initial PR described a finished MVP with a dozen tests. Independent verification found a ~400-line skeleton: build passing, &lt;strong&gt;zero test files&lt;/strong&gt;, no CI, none of the surfaces. So the sprint's first real issue was a baseline audit — a claim-vs-reality table that's still in the repo — and after that, nothing merged on a description again. Every PR was checked out locally, built, typechecked, and test-run; a green run with the PR's tests missing counted as failure. A public log of every session and its verification outcome is in the repo at &lt;code&gt;docs/copilot-usage.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That discipline earned its keep twice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One issue's mapper produced escalation records that an earlier issue's schema rejected. Two correct pieces that didn't compose — exactly the class of bug that only appears when you run the integrated system instead of admiring the parts. The schema now permits an empty target only for manual-review mappings, which is the one place it's semantically true.&lt;/li&gt;
&lt;li&gt;The final test-matrix issue closed the gap everyone knew about: the MCP server had been tested over an in-memory transport. It now has a stdio subprocess smoke test — spawn the real server, initialize, list tools, confirm unapproved execution is refused.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two honest footnotes from the tooling itself. I ran the sprint on Copilot's efficiency routing deliberately — the work was well-specified enough that cheaper, faster models plus strict verification beat premium models plus trust. And Copilot Memory, which would have helped the agent retain project context, turned out to be unreachable for personal subscribers due to a GitHub bug (the settings selector simply doesn't render). I filed a support ticket and kept building; the sprint didn't wait on it.&lt;/p&gt;

&lt;p&gt;The full test matrix and readiness assessment — including what the tests &lt;em&gt;don't&lt;/em&gt; establish — is published at &lt;code&gt;docs/status/mvp-readiness-report.md&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The test beds have their own story
&lt;/h3&gt;

&lt;p&gt;To test a migration engine you need content worth migrating, so the fixtures became projects of their own. DXS came from a Copilot Cowork prompt, built out on Lovable in two data-layer variants. The WordPress test bed is a real WordPress.com site, and seeding it turned into a relay: &lt;strong&gt;GitHub Copilot wrote the prompts; WordPress.com's own AI agent executed them&lt;/strong&gt; in wp-admin (slowly — its editor accepts only a small prompt at a time). When that stalled short of the full spec, my agent emailed WordPress's agent the remaining specification directly, agent to agent. One detail from that exchange is worth more than the anecdote: the WP agent initially didn't answer mail from an unknown agent address at all. It responded in about ninety seconds once the identical message came from the site owner's own mailbox. Agent identity and sender trust are about to be everybody's problem; here it was, in miniature, in a test fixture.&lt;/p&gt;

&lt;p&gt;The agent also flagged a real edge case unprompted: the scheduled post in the fixture is stored at 14:00 local (America/Chicago), which means its GMT value in the export reads 19:00. A migration engine that mishandles that offset publishes your launch announcement five hours late.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The run itself&lt;/strong&gt; (October 14, against the live export of wp.sandbox.migrateme.tech): the export held &lt;strong&gt;44 items&lt;/strong&gt; — 8 posts (including the draft, the private post, and the scheduled launch announcement), 9 pages up to and including the License page created that morning, 18 attachments, and 9 items of types the engine had never seen in a fixture: the site's global styles, its navigation, its header/footer/archive templates, and the four AI Guidelines documents, which migrated as documents like everything else. Planning produced &lt;strong&gt;420 field mappings: 287 deterministic, 133 sent to manual review&lt;/strong&gt; — Jetpack bookkeeping fields, author mappings, and custom fields the engine declined to guess at rather than silently drop — alongside &lt;strong&gt;310 flagged risks&lt;/strong&gt;. The dry run wrote nothing. The approved migration wrote 44 Markdown files with zero failures; posts carry faithful front matter (title, slug, date, taxonomy, featured image), and the scheduled post kept its 14:00 local date. &lt;strong&gt;Validation passed: 44 expected, 44 found, empty exception queue.&lt;/strong&gt; The honest wrinkles: post bodies retain their Gutenberg block comments rather than being rewritten to pure Markdown, colliding attachment slugs are disambiguated with deterministic suffixes instead of overwrites, and attachments migrate as metadata documents — the binaries travel separately, via WordPress's own media export.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's verified and what isn't
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Verified:&lt;/strong&gt; 41 automated tests, all passing, CI green — unit, connector contracts, golden-file comparisons, integration flows across CLI/MCP/web, checkpoint-resume equivalence, approval gates on every surface, SSRF rejection (the validator checks DNS resolutions and pins connections, refusing private/link-local/loopback targets), path-traversal and symlink containment, XSS escaping in the web flow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not yet established:&lt;/strong&gt; behavior against the full zoo of real-world, plugin-generated WXR exports (the readiness report says this plainly); correctness against a live remote CMS destination, with real credentials, throttling, and API failures — WordPress as a destination is designed into the connector roadmap, not yet built, and this post claims the architecture for it, not the implementation; AI mapping &lt;em&gt;quality&lt;/em&gt; against a live model on production data — the tests prove the safety rails, not the taste.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Three concrete places, no philosophy required:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Client content stays on the client's machine.&lt;/strong&gt; A real WXR export contains drafts, private posts, and unapproved comments — the stuff a business hasn't published and may never intend to. The AI mapper runs a local open-weight model via Ollama specifically so that content never leaves the laptop doing the migration. A hosted API would make the privacy story a terms-of-service paragraph. Local inference makes it an architectural fact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The economics work.&lt;/strong&gt; A per-migration tool can't carry per-token pricing on every field of every post of a ten-year archive and stay free for the people who need it. A local model makes the AI step's marginal cost zero — and zero marginal cost is what makes the freemium-plus-donations model above viable instead of theatrical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The AI is auditable because everything around it is open.&lt;/strong&gt; The mapper's proposals are schema-validated, candidate-checked, and logged; when the model is wrong, the failure mode is a manual-review queue, not a corrupted import. You can read every line of that because the repo is public. The open weights are one layer of a stack that's open all the way down — and for a tool whose whole pitch is "trust me with your site's history," that's not ideology. That's the feature list.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/msZ7Jt_jBKU" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The template suggests saving your agent session with DevRelay. I tried to install it when the project started; it died on a Cloudflare server error before it ever ran — and it turned out not to matter, because this project's sessions were already logged where the work happened: &lt;strong&gt;on GitHub&lt;/strong&gt;. The planning session is a public Copilot Chat share, and every implementation session is a pull request — all 16 PRs in the repo are Copilot-authored, each tied to the issue it was assigned, each with its verification outcome recorded before merge.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Mike-Demo/migrateme.tech/blob/main/docs/copilot-usage.md" rel="noopener noreferrer"&gt;Copilot usage log&lt;/a&gt; — the session-by-session evidence log: planning, per-issue sessions, verification results, including the failures&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Mike-Demo/migrateme.tech/blob/main/docs/agent-session-extract.md" rel="noopener noreferrer"&gt;Orchestration session extract&lt;/a&gt; — the companion record: my working session with the agent that directed the sprint, verified every PR, ran the test beds, and assembled this submission, redacted under a published log of what was removed and why&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://copilot.share/007e1226-4124-8210-b943-3640002840c8" rel="noopener noreferrer"&gt;The planning session&lt;/a&gt; — the Copilot Chat where the MVP plan and issue graph were designed (public share link)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Mike-Demo/migrateme.tech/pulls?q=is%3Apr" rel="noopener noreferrer"&gt;All pull requests&lt;/a&gt; — every one authored by Copilot's coding agent; the merge history is the session history&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Agents built most of this, and the post says so wherever it happened: GitHub Copilot wrote the code; a second agent verified every change, ran this project's operations, and drafted this post from the project's own records; Copilot Cowork and WordPress.com's agent built the fixtures. I set the direction, the constraints, and the acceptance bar, and I made every call about what shipped. The tools are credited in the repo, the logs are public, and the parts that failed are written down next to the parts that worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Overall prize&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of GitHub Copilot&lt;/strong&gt; — Copilot's coding agent wrote the engine across fifteen issues; Copilot Cowork authored the test bed's founding brief; Copilot even wrote the prompts that seeded the WordPress fixture. The usage log is public in the repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of a .tech Domain&lt;/strong&gt; — migrateme.tech is the product's name, its live sandbox namespace, and its future route table.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>Grass Journal: a private voice journal that wants you to put your phone down</title>
      <dc:creator>Mike “Demo” Demopoulos</dc:creator>
      <pubDate>Wed, 07 Oct 2026 02:18:13 +0000</pubDate>
      <link>https://dev.to/mpmike/grass-journal-a-private-voice-journal-that-wants-you-to-put-your-phone-down-2ini</link>
      <guid>https://dev.to/mpmike/grass-journal-a-private-voice-journal-that-wants-you-to-put-your-phone-down-2ini</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I do my best thinking on walks. Not at a desk. Halfway around the block, when a thought finally finishes itself, and I need somewhere to put it before it's gone.&lt;/p&gt;

&lt;p&gt;Grass Journal is the somewhere. It's a voice and text journal that runs entirely on your device. No account, no backend, no analytics. Your entries live in your browser's local database and nowhere else. It transcribes voice notes with Whisper tiny.en and writes optional reflections with Qwen2.5-0.5B or Gemma 2 2B IT, your pick. Every model runs on-device, in the browser. The app makes zero network requests.&lt;/p&gt;

&lt;p&gt;Your thoughts stay with you. That's the whole product.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5irhiax6628265pp9hmn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5irhiax6628265pp9hmn.jpg" alt="Grass-textured phone case at the stadium" width="800" height="1067"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Touch grass: the phone case says it before I do.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Getting people off the screen is the design brief, not a side effect. Three ways to capture a moment, each built to take seconds:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speak.&lt;/strong&gt; Hit record, talk, done. The app saves your audio before it does anything else, then transcribes on-device. Transcription fails? You still have the recording. Nothing uploads anywhere because there's nowhere to upload it to. This is the walking mode. Speak while you move.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tap.&lt;/strong&gt; The &lt;code&gt;/watch/&lt;/code&gt; page is a feeling wheel for your wrist. Eight feelings, one tap, saved in about ten seconds. I built it for the Apple Watch web viewer, which gives web pages no microphone and hijacks long-press to open a new tab. So: tap a feeling, put your wrist down, keep walking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Write.&lt;/strong&gt; A plain text editor with autosave. No toolbar fighting for your attention.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsaz1f60bq503v5jbzd00.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsaz1f60bq503v5jbzd00.gif" alt="Typing an entry with autosave" width="390" height="844"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Type, and it's saved on your device before you lift your thumbs.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's for anyone who thinks better outside and wants a journal that respects that instead of competing with it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Try it live:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://grass-journal.view.fast/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgrass-journal.view.fast%2Fog-image.jpg" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://grass-journal.view.fast/" rel="noopener noreferrer" class="c-link"&gt;
            Grass Journal
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            A private, offline-first voice and text journal. Your thoughts stay with you.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgrass-journal.view.fast%2Ffavicon.svg" width="64" height="64"&gt;
          grass-journal.view.fast
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;The 10-second version:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://grass-journal.view.fast/watch/" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;grass-journal.view.fast&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Full demo (54 seconds):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Ex0Twh7cRjg" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx6yua1jowprzvqdkkgv4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx6yua1jowprzvqdkkgv4.gif" alt="Feeling wheel walkthrough" width="390" height="844"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Tap the hub, tap a feeling, saved. Phone resolution, real interaction.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnuic4wm18jgdpqoxkppu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnuic4wm18jgdpqoxkppu.jpg" alt="Feeling wheel on Apple Watch, real device" width="800" height="1067"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The wheel on a real Apple Watch, out in the world. Ten seconds, one tap, wrist back down.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On the full app, record a voice note and watch it transcribe with the network idle. Then open the privacy screen and run the check yourself:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxh04am2jqhnnxi3sjnd6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxh04am2jqhnnxi3sjnd6.gif" alt="Privacy check running and passing" width="390" height="844"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The app's own audit, runnable by anyone: "Passed — zero network requests during the test."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The AI setup screen is where you pick your reflection model:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fru3prbw95k2wyfoy6ci0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fru3prbw95k2wyfoy6ci0.png" alt="AI setup: reflection model picker" width="707" height="4096"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I took it to the USMNT game. Getting through security was frustrating, so I opened the wheel on my watch and tapped how I felt — no data, didn't matter. Being able to capture it in the moment instead of reconstructing it later is the whole point. And having a way to continue my Fable journaling habit is good too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's verified and what isn't.&lt;/strong&gt; The challenge grades technical execution, so here's the honest version:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Voice capture, transactional save, SHA-256 integrity checks: covered end-to-end in automated tests (12/12 Playwright, 50/50 Vitest on this build).&lt;/li&gt;
&lt;li&gt;Whisper tiny.en transcription and Qwen2.5-0.5B reflection: verified on desktop Chrome with WebGPU.&lt;/li&gt;
&lt;li&gt;Offline: it's a PWA with a full offline cache. Model weights download once, then everything runs with no connection.&lt;/li&gt;
&lt;li&gt;Apple Watch: the page loads and the wheel works on a real watch. watchOS gives web pages no microphone, so there's no voice capture there. That's Apple's restriction, not a bug. It's why the wheel exists.&lt;/li&gt;
&lt;li&gt;Reflection quality: these are small models. They write short, simple reflections. I claim nothing more. No WebGPU? You get a deterministic keyword fallback instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Mike-Demo" rel="noopener noreferrer"&gt;
        Mike-Demo
      &lt;/a&gt; / &lt;a href="https://github.com/Mike-Demo/grass-journal" rel="noopener noreferrer"&gt;
        grass-journal
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A private, offline-first voice and text journal PWA. Your thoughts stay with you.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🌱 Grass Journal&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A personal project.&lt;/strong&gt; Built by Mike Demopoulos for personal use and shared
publicly as-is. No warranties, no support queue — just the app as it runs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A private, offline-first voice and text journal — as a Progressive Web App.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Core promise: “Your thoughts stay with you.”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;No account. No backend. No cloud. No analytics. No ads. No remote transcription or
hosted AI. Entries, recordings, transcripts, and reflections live in IndexedDB on
your device. On-device AI (Whisper transcription, Qwen reflection) is optional
manually triggered, and never blocks saving.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Product principles (in priority order)&lt;/h2&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Never lose the original entry.&lt;/li&gt;
&lt;li&gt;Never send journal content to an external service.&lt;/li&gt;
&lt;li&gt;The journal works without AI.&lt;/li&gt;
&lt;li&gt;AI never blocks saving.&lt;/li&gt;
&lt;li&gt;Audio is saved before transcription begins.&lt;/li&gt;
&lt;li&gt;Original content is authoritative; AI output is optional metadata.&lt;/li&gt;
&lt;li&gt;No user account. 8. No cloud service.&lt;/li&gt;
&lt;li&gt;Brief interactions — then back to real life.&lt;/li&gt;
&lt;li&gt;Privacy claims are…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Mike-Demo/grass-journal" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Personal project, MIT. The repo has everything: React + TypeScript + Vite PWA, Dexie.js over IndexedDB, MediaRecorder capture, encrypted backups (AES-GCM-256, PBKDF2 with 600k iterations), and the on-device AI workers.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Open weights all the way down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Whisper tiny.en&lt;/strong&gt; (MIT) handles every transcription, on-device, through Transformers.js in a Web Worker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reflection&lt;/strong&gt; runs on-device through WebLLM, also in a worker, and you choose the model: &lt;strong&gt;Qwen2.5-0.5B-Instruct&lt;/strong&gt; (Apache 2.0, default, ~450 MB) or &lt;strong&gt;Gemma 2 2B IT&lt;/strong&gt; (Gemma Terms of Use, ~1.5 GB, usually richer). The worker loads whichever you picked. Every saved reflection records the model ID and the versioned system prompt, so you can always trace what wrote it.&lt;/li&gt;
&lt;li&gt;The prompt asks for JSON and the client validates the reply, retrying once with a repair prompt when parsing fails. I skipped grammar-constrained decoding on purpose: WebLLM's xgrammar WASM won't initialize on iOS WebKit. Plain code validation instead.&lt;/li&gt;
&lt;li&gt;No WebGPU, no problem: reflection falls back to deterministic on-device keyword tags. AI never blocks saving. The entry saves first, always.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full credits for every library, model, and tool — with licenses — are on the &lt;a href="https://grass-journal.view.fast/#/open-source" rel="noopener noreferrer"&gt;open-source credits page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And the disclosure the challenge asks for: I built this October 5–6, inside the challenge window, with an AI coding agent (Muse). I set the architecture, the privacy constraints, every product call. The agent wrote code; I verified it against the test suites and real devices.&lt;/p&gt;

&lt;p&gt;Yes, there's irony in using a cloud-scale model to build the thing that frees you from cloud-scale models. I'll take it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;I don't want my journal entries on someone else's server. That's the whole reason this app exists in this form.&lt;/p&gt;

&lt;p&gt;Every journaling app with cloud AI asks you to make the same trade: hand over your most private thoughts so a model you can't see can process them on hardware you don't control. The privacy promise is always a paragraph in the terms of service. I've read enough of those paragraphs to know what they're worth.&lt;/p&gt;

&lt;p&gt;Open weights end the trade. Whisper, Qwen, and Gemma run on my device, in my browser. Nothing leaves. And you don't have to take my word for it, which is the part I like best: the privacy screen runs a check that intercepts every network request and shows you the result. Try getting that from a closed API. The most sensitive part of their app is a black box they rent by the token. Mine is code you can read and models you can download yourself.&lt;/p&gt;

&lt;p&gt;Three more places the open approach wins, concretely:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It works where journals get written.&lt;/strong&gt; I take this outside. A closed-API journal dies without signal, which is exactly when you want it. That's not a limitation; it's a design contradiction. Local inference resolves it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It costs nothing per entry.&lt;/strong&gt; Metered APIs make you ration the feature. A local model makes it free to use and free to ignore. I reflect on walks, not on budgets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can change its mind.&lt;/strong&gt; Two models on one screen, switch whenever. The model is a file. Not a vendor relationship, not a pricing page.&lt;/p&gt;

&lt;p&gt;The closed alternative isn't a worse journal. It's a journal that ships your inner life to infrastructure you don't control. I built the other one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Overall prize&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt; — Gemma 2 2B IT runs locally via WebLLM as a first-class reflection model. Install it from the AI setup screen, and the entry screen uses it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hat tip
&lt;/h2&gt;

&lt;p&gt;This build was inspired by apps that take inner life seriously:&lt;/p&gt;


&lt;div class="instagram-position"&gt;
  &lt;blockquote class="instagram-media"&gt;
    &lt;div&gt;
      &lt;a href="https://www.instagram.com/accounts/" rel="noopener noreferrer"&gt;
        View this post on Instagram
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/blockquote&gt;
  
&lt;/div&gt;



&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://getfableapp.com/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgetfableapp.com%2Fscreenshots%2Ffable_app.png" height="1452" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://getfableapp.com/" rel="noopener noreferrer" class="c-link"&gt;
            Fable - Live a Better Story Through AI Journaling
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            AI-powered journaling that reveals the epic story your life is already telling
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgetfableapp.com%2Ffavicon.ico" width="" height=""&gt;
          getfableapp.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class="instagram-position"&gt;
  &lt;blockquote class="instagram-media"&gt;
    &lt;div&gt;
      &lt;a href="https://www.instagram.com/accounts/" rel="noopener noreferrer"&gt;
        View this post on Instagram
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/blockquote&gt;
  
&lt;/div&gt;


</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>gemma</category>
      <category>ai</category>
    </item>
    <item>
      <title>QueerCade: Both Sanity Challenge Paths, One Arcade</title>
      <dc:creator>Mike “Demo” Demopoulos</dc:creator>
      <pubDate>Sun, 04 Oct 2026 22:59:47 +0000</pubDate>
      <link>https://dev.to/mpmike/queercade-both-sanity-challenge-paths-one-arcade-fm4</link>
      <guid>https://dev.to/mpmike/queercade-both-sanity-challenge-paths-one-arcade-fm4</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/qmOVDUVw1TM" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I built QueerCade — a curated arcade of LGBTQ+ video games — through both paths of the Sanity challenge. One dataset powers all of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Path One: Ship an Agent That Queries Real Content
&lt;/h2&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/mpmike/queercade-2997" class="crayons-story__hidden-navigation-link"&gt;QueerCade (Part 1): Ship an Agent That Queries Real Content&lt;/a&gt;
    &lt;div class="crayons-article__cover crayons-article__cover__image__feed"&gt;
      &lt;iframe src="https://www.youtube.com/embed/_rTiewqMaYs" title="QueerCade (Part 1): Ship an Agent That Queries Real Content"&gt;&lt;/iframe&gt;
    &lt;/div&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/mpmike/queercade-2997" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Sanity Challenge Path One Submission&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/mpmike" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F389717%2Fa648f865-55d3-4e9f-98cf-e832c4d376a2.jpg" alt="mpmike profile" class="crayons-avatar__image" width="800" height="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/mpmike" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Mike “Demo” Demopoulos
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Mike “Demo” Demopoulos
                
                
              
              &lt;div id="story-author-preview-content-4710147" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/mpmike" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F389717%2Fa648f865-55d3-4e9f-98cf-e832c4d376a2.jpg" class="crayons-avatar__image" alt="" width="800" height="800"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Mike “Demo” Demopoulos&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/mpmike/queercade-2997" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Sep 21&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/mpmike/queercade-2997" id="article-link-4710147"&gt;
          QueerCade (Part 1): Ship an Agent That Queries Real Content
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/sanitychallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;sanitychallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/sanity"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;sanity&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/mpmike/queercade-2997#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              1&lt;span class="hidden s:inline"&gt;&amp;nbsp;comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;The QueerCade Discovery Guide is an AI agent that recommends games, characters, developers, and studios — answering only from the Sanity dataset (3,500+ documents). It never invents a game; if something isn't in the data, it says so.&lt;/p&gt;

&lt;h2&gt;
  
  
  Path Two: Vibe-Code Something Strange
&lt;/h2&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/mpmike/queercade-part-2-vibe-code-something-strange-an-arcade-of-queer-games-on-sanity-5c2c" class="crayons-story__hidden-navigation-link"&gt;QueerCade (Part 2): Vibe-Code Something Strange — an Arcade of Queer Games on Sanity&lt;/a&gt;
    &lt;div class="crayons-article__cover crayons-article__cover__image__feed"&gt;
      &lt;iframe src="https://www.youtube.com/embed/rRceuuhhMTk" title="QueerCade (Part 2): Vibe-Code Something Strange — an Arcade of Queer Games on Sanity"&gt;&lt;/iframe&gt;
    &lt;/div&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/mpmike/queercade-part-2-vibe-code-something-strange-an-arcade-of-queer-games-on-sanity-5c2c" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Sanity Challenge Path Two Submission&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/mpmike" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F389717%2Fa648f865-55d3-4e9f-98cf-e832c4d376a2.jpg" alt="mpmike profile" class="crayons-avatar__image" width="800" height="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/mpmike" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Mike “Demo” Demopoulos
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Mike “Demo” Demopoulos
                
                
              
              &lt;div id="story-author-preview-content-4767777" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/mpmike" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F389717%2Fa648f865-55d3-4e9f-98cf-e832c4d376a2.jpg" class="crayons-avatar__image" alt="" width="800" height="800"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Mike “Demo” Demopoulos&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/mpmike/queercade-part-2-vibe-code-something-strange-an-arcade-of-queer-games-on-sanity-5c2c" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Sep 29&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/mpmike/queercade-part-2-vibe-code-something-strange-an-arcade-of-queer-games-on-sanity-5c2c" id="article-link-4767777"&gt;
          QueerCade (Part 2): Vibe-Code Something Strange — an Arcade of Queer Games on Sanity
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/sanitychallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;sanitychallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/sanity"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;sanity&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/mpmike/queercade-part-2-vibe-code-something-strange-an-arcade-of-queer-games-on-sanity-5c2c#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;The arcade itself: a retro 8-bit pixel-art storefront with the Queer Character Constellation (870+ LGBTQ+ characters plotted as stars across decades) and the Emoji Game Oracle. Every screen, filter, and graph reads from Sanity via GROQ — no other content database.&lt;/p&gt;

&lt;p&gt;One content lake, three experiences: a storefront, an MCP-queryable agent, and a celestial graph. Built on Sanity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Inspired by
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://x.com/gaymingmag" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fprofile_images%2F2086392458733146112%2FSMAlOhUg_200x200.jpg" height="200" class="m-0" width="200"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://x.com/gaymingmag" rel="noopener noreferrer" class="c-link"&gt;
            Gayming Magazine (@gaymingmag) / X
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            The home of queer geek culture 🏳️‍⚧️🏳️‍🌈🎮🕹️

Using this platform to celebrate LGBTQ+ excellence in an act of rebellion against its owner. 💪
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fx.com%2Ffavicon.ico" width="32" height="32"&gt;
          x.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  AI Disclosure
&lt;/h2&gt;

&lt;p&gt;AI assistance for this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Superhuman GO for MCP agent testing&lt;/li&gt;
&lt;li&gt;Microsoft Copilot for idea planning&lt;/li&gt;
&lt;li&gt;GitHub Copilot and Lovable for code&lt;/li&gt;
&lt;li&gt;Grammarly for editing review, with human edits&lt;/li&gt;
&lt;li&gt;Balsamiq AI for wireframe layouts&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>sanitychallenge</category>
      <category>sanity</category>
      <category>ai</category>
    </item>
    <item>
      <title>Eat Well AI: an in-browser AI that finds restaurants for every diet</title>
      <dc:creator>Mike “Demo” Demopoulos</dc:creator>
      <pubDate>Sun, 04 Oct 2026 21:20:09 +0000</pubDate>
      <link>https://dev.to/mpmike/eat-well-ai-an-in-browser-ai-that-finds-restaurants-for-every-diet-424l</link>
      <guid>https://dev.to/mpmike/eat-well-ai-an-in-browser-ai-that-finds-restaurants-for-every-diet-424l</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I'm excited to take part in the Hacktoberfest Weekend Challenge: Build for a Friend, where makers worldwide solve real problems for people they care about.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Eat Well AI&lt;/strong&gt; empowers people with dietary needs to discover restaurants that actually welcome them. Forget complicated filters—just express what you want in your own words, and Eat Well AI does the rest. Find food that fits your life, not just your diet.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"vegan pizza in Chicago"&lt;br&gt;
"kosher in Miami"&lt;br&gt;
"gluten free tacos"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An open-source algorithm that runs in your browser. It converts your sentence into search filters. Isn't that pretty neat? There's no need for servers or API keys since your sentences remain on your device.&lt;/p&gt;

&lt;p&gt;I built Eat Well AI for my friend Miriam, who keeps kosher and often struggles to find places to eat when we travel. As a vegan myself, our outings always meant an exhausting search for spots that welcome both our needs. Eat Well AI finally answers that question: Where can we both eat, easily and confidently?&lt;/p&gt;

&lt;p&gt;The search now spans over 1,000 restaurants in 37 cities, each carefully labeled for vegan, vegetarian, gluten-free, kosher, and halal options. Results appear as rich, interactive cards—complete with directions—so users can go from query to table in moments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Try it live: &lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://eat-well-ai.view.fast/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feat-well-ai.view.fast%2Fog-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://eat-well-ai.view.fast/" rel="noopener noreferrer" class="c-link"&gt;
            Eat Well — dietary restaurant finder for the Tufty 2350 badge
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Playable web demo of Eat Well: 557 vegan, vegetarian, gluten-free, kosher and halal restaurant picks across 14 US cities, searchable in plain English with Qwen3 running in your browser, with a MapQuest QR code for every spot.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feat-well-ai.view.fast%2Ffavicon-32x32.png" width="32" height="32"&gt;
          eat-well-ai.view.fast
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;If you use Chrome or Edge on a device that supports WebGPU, the model will download once (approximately 340MB) and afterwards all the features will function on your device.&lt;/p&gt;

&lt;p&gt;Watch the 55-second demo:&lt;/p&gt;

&lt;p&gt;URL:   &lt;iframe src="https://www.youtube.com/embed/aKCENHBXHqs" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Type it in clear English:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsnim5yg35hvzww79fmsc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsnim5yg35hvzww79fmsc.gif" alt="Query typing demo" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Results with map QR codes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fconk0h6uh4dpzy6sihlr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fconk0h6uh4dpzy6sihlr.gif" alt="Results demo" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The admin side, adding a listing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9os034pj8nh8ot0l5d92.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9os034pj8nh8ot0l5d92.gif" alt="Admin demo" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F91rgr7zn99g37y4kplaw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F91rgr7zn99g37y4kplaw.gif" alt="1,017 restaurants across 37 cities" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Mike-Demo/eat-well-ai" rel="noopener noreferrer"&gt;https://github.com/Mike-Demo/eat-well-ai&lt;/a&gt; — MIT licensed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;The stack consists of plain HTML, CSS, and JavaScript served as static files; the restaurant database is in a single &lt;code&gt;data.js&lt;/code&gt; file, and a search script filters it.&lt;/p&gt;

&lt;p&gt;Alibaba's open-weight Qwen3-0.6B model can be run in the browser via WebLLM and WebGPU; I have hosted the model weights on the same static host, the page never makes a call to HuggingFace or any other API at runtime.&lt;/p&gt;

&lt;p&gt;When you enter a query, the system interprets it and converts it into a formatted filter consisting of information about diets, the city, and cuisine keywords. The model's output is constrained using a JSON grammar (through WebLLM's &lt;code&gt;response_format&lt;/code&gt;), which ensures that malformed output cannot occur. A model with a size of 0.6B will not comply with the instruction to "reply in JSON" by itself; the grammar overcomes this by design. If the model engine fails, a simple keyword parser then takes over so that the search can still function.&lt;/p&gt;

&lt;p&gt;The JavaScript filters the restaurants and then displays the cards.&lt;/p&gt;

&lt;p&gt;Eat Well AI evolved from Eat Well, the version I created for the Pimoroni Tufty 2350 microcontroller badge, which had 557 restaurants, physical buttons, and no possibility of using AI; the app for that badge operates in a panel below the search box and uses the same code and pixel art.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Open Innovation Matters
&lt;/h2&gt;

&lt;p&gt;The hosted AI API was obviously the quickest way out and I decided not to use it for three reasons.&lt;/p&gt;

&lt;p&gt;Privacy is the most important consideration. Individual dietary requirements are a matter for the person concerned. When you enter a query such as "kosher near me" you are giving information about both your religion and your location. The model operates on your device and so that sentence never gets sent to a server.&lt;/p&gt;

&lt;p&gt;The cost is a close second. With hosted models you are charged on a per-query basis. This one has no cost per query. The entire cost is due to static file hosting.&lt;/p&gt;

&lt;p&gt;Control is third; with open weights I am able to self-host the model, replace it at a later stage, and adjust the prompt. Since the small model was ignoring my JSON instructions, I restricted its output using a grammar rather than submitting a support request. Before shipping, I checked the prompt by running the same weights on my own machine.&lt;/p&gt;

&lt;p&gt;Turning the weights open turned what had been a weekend project into one that I could give to a friend without having to hand her any of my data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspired by
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://x.com/HappyCow" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fprofile_images%2F1575483069271838721%2F_bDFkuwN_200x200.png" height="200" class="m-0" width="200"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://x.com/HappyCow" rel="noopener noreferrer" class="c-link"&gt;
            HappyCow (@HappyCow) / X
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Discover vegan food near you 🌏 #1 vegan app 🐮 180+ countries, 4M+ #HappyCowmunity 🌱 Grow the moo-vement together 💜 Download the app!
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fx.com%2Ffavicon.ico" width="32" height="32"&gt;
          x.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  AI Disclosure
&lt;/h2&gt;

&lt;p&gt;AI tools used on this project and write-up, and how:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Grammarly&lt;/strong&gt; — edited this post: grammar and spelling fixes, tone passes with its humanizer (Naturalist profile), AI-phrase detection and rewrites, and "make it more impactful" suggestions. Every suggestion was reviewed and approved by the author before applying.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GPTZero&lt;/strong&gt; — scored drafts for AI-likeness during editing, used as a rough signal rather than a verdict.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pexo&lt;/strong&gt; — generated the 55-second demo video from the project brief (4K, no voiceover).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adobe Firefly&lt;/strong&gt; — generated the pixel art used in the app and badge UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Qwen3-0.6B (Alibaba)&lt;/strong&gt; — the open-weight model that powers the app's in-browser natural-language search, running locally via WebLLM and WebGPU.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything else — the code, the dataset, the MapQuest integration, and the final words — is the author's own work.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
    </item>
    <item>
      <title>Can LLMs audit multi-agent prompts? I made them grade my robot football team.</title>
      <dc:creator>Mike “Demo” Demopoulos</dc:creator>
      <pubDate>Thu, 01 Oct 2026 16:16:19 +0000</pubDate>
      <link>https://dev.to/mpmike/can-llms-audit-multi-agent-prompts-i-made-them-grade-my-robot-football-team-40pf</link>
      <guid>https://dev.to/mpmike/can-llms-audit-multi-agent-prompts-i-made-them-grade-my-robot-football-team-40pf</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/kaggle-2026-09-23"&gt;Kaggle Benchmarking Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What task(s) did you run?
&lt;/h2&gt;

&lt;p&gt;In the first Agentic Football Cup — a simulated football league in which each 'player' on the teams is an LLM agent controlled using a prompt file — I conduct a manual audit of those prompt files before each match window, looking for bugs such as collisions between forwards in zones, loopholes in the handoff procedures between defenders, and scope conflicts in the anti-spam rules. This process is time-consuming.&lt;/p&gt;

&lt;p&gt;There was a desire to know: could a large language model carry out the audit instead? And more importantly – could I place &lt;em&gt;trust&lt;/em&gt; in it?&lt;/p&gt;

&lt;p&gt;So I created a benchmark that acts as a junior auditor and evaluates the model against the ground truth I already have. The task provides the model with two items:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A retired team-prompt JSON (one of three Bugle Crowns builds)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The same stress-test audit prompt a human would follow&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The system must provide the structured findings—including the defect ID, a GREEN/YELLOW/RED flag, and a direct quotation of the evidence—and also give one final decision, either SHIP AS-IS, FIX-THEN-SHIP, or DO NOT SHIP. Provide only the findings, with no rewrites.&lt;/p&gt;

&lt;p&gt;The three builds are the clever part:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;v2.5A.1&lt;/strong&gt; — a faulty version containing three known defects (a collision in the defensive-corner zone, a loophole in the intercept lane-handoff, and a conflict between the anti-spam scope). The audit has to identify all three.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;v2.5A.2&lt;/strong&gt; is the fixed control build, so any finding by RED in this instance is a hallucinated false positive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;v2.5A.5&lt;/strong&gt; — a more difficult version containing eight possible findings of varying severity, designed to distinguish between competent auditors and those who are good at their job.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scoring has three components: recalling known defects, ensuring there are no REDs on the control build, and verifying that the final decision matches the ground truth. The entire process is a Kaggle benchmark task with structured output so that a machine can check each run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Against which models did you test it?
&lt;/h2&gt;

&lt;p&gt;Three models in the final lineup, nine clean runs (every model against every build):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The tests comparing google/gemini-2.5-flash and google/gemini-2.5-pro aim to determine whether the larger model is actually the better auditor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The small OpenAI model, openai/gpt-5.4-mini, was used to see whether a lightweight model can audit.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two further attempts were made and had to be abandoned. anthropic/claude-sonnet-4-5 failed to get a single run: the Kaggle LLM gateway returned HTTP 429 ("heavy load") on all three attempts, twice, four(ish) hours apart — this was due to capacity ceilings on the part of the provider, not because of an invalid model ID. deepseek-ai/deepseek-r1-0528 did manage to access the model once, but the benchmark SDK's response parser was unable to process its reasoning traces. The fact that a reasoning model has reasoning that breaks the system is itself a finding, but the model cannot be used for scoring. (This is because no model from Meta is available on the Kaggle platform, which is the reason DeepSeek was assigned to that position in the first place.)&lt;/p&gt;

&lt;p&gt;Each run had its own new chat context, with roughly 7,000 input tokens per call. Total spend was about \$0.52 of the \$10 daily quota, including failed attempts (rate-limited calls cost nothing).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1uddfim6iyxe9grygiw3.GIF" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1uddfim6iyxe9grygiw3.GIF" alt="Benchmark lineup: 5 models attempted, 3 scored; Claude and DeepSeek marked DNF" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the main insights?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. All the models advised adopting the FIX-THEN-SHIP approach in all cases, including those relating to the clean build.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The headline is this: the v2.5A.2 control build contains no defects and should therefore be shipped as-is. Yet all three of the working models still marked it FIX-THEN-SHIP. They are cautious rather than precise. Although none produced any RED findings on the clean build (since the no-RED check passed at all locations), none would approve it. If you used one of these as your audit gate, nothing would ever get shipped.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8dh5dcdm1c5a9fsvp58h.GIF" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8dh5dcdm1c5a9fsvp58h.GIF" alt="Verdict grid: all 9 runs returned FIX-THEN-SHIP; the 3 control-build tiles flip red — correct verdict was SHIP AS-IS" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Recall is inadequate since the auditors fail to detect actual bugs.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the buggy v2.5A.1 and three known defects in the prompt, only gpt-5.4-mini picked up any of them—two out of the three. Both of the Gemini models caught none of the defects in the sweep runs. You wouldn't hire an auditor who misses two out of three known defects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ayvez50qj43j23x8rk5.GIF" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ayvez50qj43j23x8rk5.GIF" alt="Bug recall on the 3 known defects: GPT-5.4 mini 2/3, both Gemini models 0/3" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The hard set puts the models apart.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With respect to the eight findings on v2.5A.5, gemini-2.5-pro identified four, flash found three, and gpt-5.4-mini found none. The more powerful model did, in fact, justify its cost in this instance—though it is worth noting the irony that gemini-2.5-pro was the most effective at detecting bugs and yet still failed to approve the clean build.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fprd630g4cl88jq6su4n5.GIF" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fprd630g4cl88jq6su4n5.GIF" alt="Hard-set results: Gemini Pro 4/8, Gemini Flash 3/8, GPT-5.4 mini 0/8" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Outputs vary run to run.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first smoke test I ran picked up the defect related to the D1 corner collision; however, a resweep of the same model with the same build did not. When conducting benchmarking of auditors, a single run is insufficient — and if you are &lt;em&gt;using&lt;/em&gt; an LLM auditor, you must know that its answers are inconsistent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. The main point: models check themselves like anxious beginners.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Flag every item, commit to nothing, and fail to identify the real bugs while refusing to mark the clear ones. This is precisely the kind of failure mode you should look for before letting an LLM be involved in any production prompt analysis—and it is the opposite of what the marketing claims these models are good at.&lt;/p&gt;

&lt;p&gt;The next things I would look at are having a judge-LLM review the borderline YELLOW findings to see whether a second model can prioritize those that the first one has flagged; examining the latency and cost associated with each model (since which auditor would you really hire on a per-dollar basis?); and carrying out more builds, some of which involve cases where the correct decision is actually ambiguous.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where can we see it?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.kaggle.com/code/michaeltdemopoulos/can-llms-audit-multi-agent-prompts-bugle-crowns" rel="noopener noreferrer"&gt;The Benchmark Notebook&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  On X
&lt;/h2&gt;

&lt;p&gt;Pre:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2105692069050077395-329" src="https://platform.twitter.com/embed/Tweet.html?id=2105692069050077395"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2105692069050077395-329');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2105692069050077395&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Post:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2106153217344110921-15" src="https://platform.twitter.com/embed/Tweet.html?id=2106153217344110921"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2106153217344110921-15');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2106153217344110921&amp;amp;theme=dark"
  }



&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>kagglechallenge</category>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>QueerCade (Part 2): Vibe-Code Something Strange — an Arcade of Queer Games on Sanity</title>
      <dc:creator>Mike “Demo” Demopoulos</dc:creator>
      <pubDate>Tue, 29 Sep 2026 01:40:07 +0000</pubDate>
      <link>https://dev.to/mpmike/queercade-part-2-vibe-code-something-strange-an-arcade-of-queer-games-on-sanity-5c2c</link>
      <guid>https://dev.to/mpmike/queercade-part-2-vibe-code-something-strange-an-arcade-of-queer-games-on-sanity-5c2c</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/sanity-2026-09-16"&gt;Sanity Challenge, Path Two: Vibe-Code Something Strange&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;QueerCade is a retro 8-bit pixel-art game database containing LGBTQ+ video games, constructed using TanStack Start, React 19, and the NES.css design system; it includes curated collections such as cozy queer games, visual novels, and dating sims, allows users to keep track of their personal library, and offers two enjoyable methods of exploring queer game history.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://queercade.mikedemo.dev/constellation" rel="noopener noreferrer"&gt;Queer Character Constellation&lt;/a&gt; is an interactive stellar display that plots more than 870 carefully selected LGBTQ+ characters as stars. Users are able to pan around, zoom in and out, and switch between different layers of constellations which link characters from various franchises and periods based on common identity aspects (such as lesbian, gay, bisexual, trans, non-binary, and asexual), the decades in which they were released (ranging from the early 1980s pioneers to contemporary independent games), and narrative stereotypes. When any star is clicked on, information about the individual appears, together with portraits of the cast, the sources, and a direct link to the game itself in the arcade.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://queercade.mikedemo.dev/emoji" rel="noopener noreferrer"&gt;Emoji Game Oracle&lt;/a&gt; lets you select 3 to 5 emojis covering mood, vibe, setting, and playstyle, after which an AI agent picks one custom match from the arcade and provides an in-character, retro-style explanation.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Live at &lt;a href="https://queercade.mikedemo.dev" rel="noopener noreferrer"&gt;QueerCade live site&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Sanity isn't a sidecar; it is the whole content backend, since all screens, filters, searches, and graphs obtain their data from Sanity through GROQ and there is no other content database.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Sanity powers the app
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Controls for the studio field and human-in-the-loop curation. Queer history in gaming is complex, controversial, and generally not recorded in mainstream gaming databases. To ensure that the curation process was thorough, we set up custom controls for the studio field:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Status gates: An editorial status radio control (which goes through the stages of imported → under review → approved → featured) makes sure that raw automated syncs are never made available to the public app or agent tools until they have been checked.
Editors create structured character arrays by providing dedicated input fields for the verified names of the characters, for the source citations (sourceUrl), and for the controlled tag selectors relating to identityTags and narrativeTropes (for example, coming-out-arc, found-family, playable-protagonist*).&lt;/li&gt;
&lt;li&gt;Editorial isolation means that fields such as editorNotes, sources, and character arrays are kept out of reach of the automated sync engine.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Instead, we use a pipeline, not a spreadsheet. The games come in from the IGDB API, are normalized, and are then written to Sanity via a server-side client (the token is stored in the cloud secrets and is never kept in the browser). Each time a sync runs, an importRecord document is logged—this keeps a record of what was created, updated, refreshed, and skipped. Strict enforcement of field ownership lets the IGDB machine metadata (such as ratings, covers, and release dates) refresh cleanly without overwriting human editorial entries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;With a planned approach and no unnecessary client-side bloat, all GROQ queries are located in the file src/lib/sanity/queries.ts. The constellation is able to fetch more than 800 curated character records that are embedded within games through a single projection, joining in the game metadata, the release years, the normalized identities, and the IGDB cast portraits to form a deterministic force-directed graph with no redundant client calls.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Image optimization runs in real time; the book covers and character portraits pass through &lt;a class="mentioned-user" href="https://dev.to/sanity"&gt;@sanity&lt;/a&gt;/image-url with responsive sizing and retro borders — no separate asset pipeline needed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The strange part
&lt;/h2&gt;

&lt;p&gt;In most content management systems, character data is treated as a series of static items placed at the end of an article. About 'Vibe-Code Something Strange', I asked what might happen if an editorial CMS acted as the physics engine for a retro space map.&lt;/p&gt;

&lt;p&gt;The nested document model used by Sanity regards character identities, tropes, and release years as dimensional metadata. Since the Studio field constraints confirm that identity tokens are clean and relationships are verified, an HTML5 Canvas can read the array directly from GROQ, turn the characters into nodes in a seeded d3-force simulation, and link the stars across the decades using sparse ring algorithms. Thus, a character from a 1993 point-and-click adventure can connect to the protagonist of a 2024 indie RPG through a common identity tag authored in Sanity Studio.&lt;/p&gt;

&lt;p&gt;Together with the Path One Sanity MCP agent (the Emoji Oracle), the same Sanity dataset powers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A retro pixel-art storefront&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An AI agent queryable through MCP&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An interactive celestial graph visualization&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One content lake offers three entirely different interactive experiences.&lt;/p&gt;

&lt;h2&gt;
  
  
  By the numbers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;746 games, 930 companies, 79 platforms, 22 genres&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;874 interactive character stars plotted across decades in the Constellation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;4 curated collections, all human-assembled in Sanity Studio&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;1,754 tracked import operations with full change-history audit trails&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;0 content databases besides Sanity&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Live Site: &lt;a href="https://queercade.mikedemo.dev" rel="noopener noreferrer"&gt;QueerCade live site&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Queer Character Constellation: &lt;a href="https://queercade.mikedemo.dev/constellation" rel="noopener noreferrer"&gt;Queer Character Constellation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Emoji Game Oracle: &lt;a href="https://queercade.mikedemo.dev/emoji" rel="noopener noreferrer"&gt;Emoji Game Oracle&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Code: &lt;a href="https://github.com/Mike-Demo/queer-game-vault" rel="noopener noreferrer"&gt;Queer Game Vault on GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/mpmike/queercade-2997"&gt;Path One (the agent)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Sanity Project Details: Project ID: tzh8tziu&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo:
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://queercade.mikedemo.dev/constellation" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fqueercade.mikedemo.dev%2Fog-image.png" height="427" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://queercade.mikedemo.dev/constellation" rel="noopener noreferrer" class="c-link"&gt;
            Queer Character Constellation — QueerCade
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Explore LGBTQ+ video game characters as stars connected by identity, release era, and verified narrative tropes.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fqueercade.mikedemo.dev%2Ffavicon.png" width="64" height="64"&gt;
          queercade.mikedemo.dev
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/j_MMo2qaukI" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/B8mKqX_jpf4" width="710" height="399"&gt;
  &lt;/iframe&gt;


&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I tried to use the knowledge base, but it had a limit on the number of documents. I contacted Sanity support and Discord support, and unfortunately, using the knowledge base MCP wasn't possible, which is why I connected to the standard dataset MCP instead.&lt;/p&gt;




&lt;h2&gt;
  
  
  On Instagram
&lt;/h2&gt;


&lt;div class="instagram-position"&gt;
  &lt;blockquote class="instagram-media"&gt;
    &lt;div&gt;
      &lt;a href="https://www.instagram.com/reel/Dd7NixUAgyM/" rel="noopener noreferrer"&gt;
        View this post on Instagram
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/blockquote&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  On X
&lt;/h2&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2105720470653804830-353" src="https://platform.twitter.com/embed/Tweet.html?id=2105720470653804830"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2105720470653804830-353');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2105720470653804830&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspired by
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://x.com/gaymingmag" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fprofile_images%2F2086392458733146112%2FSMAlOhUg_200x200.jpg" height="200" class="m-0" width="200"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://x.com/gaymingmag" rel="noopener noreferrer" class="c-link"&gt;
            Gayming Magazine (@gaymingmag) / X
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            The home of queer geek culture 🏳️‍⚧️🏳️‍🌈🎮🕹️

Using this platform to celebrate LGBTQ+ excellence in an act of rebellion against its owner. 💪
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fx.com%2Ffavicon.ico" width="32" height="32"&gt;
          x.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  AI Disclosure
&lt;/h2&gt;

&lt;p&gt;AI assistance for this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Superhuman GO for MCP agent testing&lt;/li&gt;
&lt;li&gt;Microsoft Copilot for idea planning&lt;/li&gt;
&lt;li&gt;GitHub Copilot and Lovable for code&lt;/li&gt;
&lt;li&gt;Grammarly for editing review, with human edits&lt;/li&gt;
&lt;li&gt;Balsamiq AI for wireframe layouts&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>sanitychallenge</category>
      <category>sanity</category>
      <category>ai</category>
    </item>
    <item>
      <title>QueerCade (Part 1): Ship an Agent That Queries Real Content</title>
      <dc:creator>Mike “Demo” Demopoulos</dc:creator>
      <pubDate>Mon, 21 Sep 2026 19:59:38 +0000</pubDate>
      <link>https://dev.to/mpmike/queercade-2997</link>
      <guid>https://dev.to/mpmike/queercade-2997</guid>
      <description>&lt;h2&gt;
  
  
  QueerCade (Part 1): Ship an Agent That Queries Real Content
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/sanity-2026-09-16"&gt;Sanity Challenge, Path One: Ship an Agent That Queries Real Content&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;QueerCade is an arcade featuring LGBTQ+ video games — titles that have&lt;br&gt;
been carefully selected on the basis of their queer characters, stories,&lt;br&gt;
themes, and creators. For Path One I created the &lt;strong&gt;QueerCade Discovery&lt;br&gt;
Guide, which is an AI agent designed to assist people in finding&lt;/strong&gt;&lt;br&gt;
games, characters, developers, studios, and aspects of queer gaming&lt;br&gt;
history, and it only responds based on the current Sanity dataset. It&lt;br&gt;
never makes up a game, a developer, a character, or a fact; if something&lt;br&gt;
is not in the dataset it states this and instead provides the nearest&lt;br&gt;
actual alternative.&lt;/p&gt;
&lt;h2&gt;
  
  
  The dataset
&lt;/h2&gt;

&lt;p&gt;One Sanity project (tzh8tziu, production dataset) holds the entire&lt;br&gt;
corpus:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Content type&lt;/th&gt;
&lt;th&gt;Documents&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;game&lt;/td&gt;
&lt;td&gt;746&lt;/td&gt;
&lt;td&gt;Titles, IGDB metadata, editorial status, relationships&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;company&lt;/td&gt;
&lt;td&gt;930&lt;/td&gt;
&lt;td&gt;Developers, publishers, involved companies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;platform&lt;/td&gt;
&lt;td&gt;79&lt;/td&gt;
&lt;td&gt;Consoles, PC, mobile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;genre&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;Taxonomy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gameCollection&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Curated lists (cozy games, visual novels, …)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;importRecord&lt;/td&gt;
&lt;td&gt;1,754&lt;/td&gt;
&lt;td&gt;Every pipeline operation, tracked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;contentPage / siteSettings&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Editorial pages, global config&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Three thousand and five hundred documents&lt;/strong&gt;, linked together by&lt;br&gt;
references: game.developer refers to the company, game.genres[] refers&lt;br&gt;
to the genre, game.platforms[] refers to the platform, and&lt;br&gt;
gameCollection.games[] refers to the game. The agent does not carry&lt;br&gt;
out keyword searches; instead, it navigates this graph.&lt;/p&gt;
&lt;h2&gt;
  
  
  How the agent connects
&lt;/h2&gt;

&lt;p&gt;Hitting the wall is something everyone encounters: the Sanity Knowledge&lt;br&gt;
Base has a limit of 150 documents, and this collection has over 3,500.&lt;br&gt;
Therefore, I completely bypassed the Knowledge Base and went &lt;strong&gt;straight to the Sanity Context MCP endpoint&lt;/strong&gt;, enclosing it in a custom&lt;br&gt;
Superhuman GO pack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MCP server:&lt;/strong&gt; &lt;a href="https://api.sanity.io/v1/context/organizations/ooowekfml/mcp/queercade-mcp" rel="noopener noreferrer"&gt;Sanity Context MCP endpoint&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The pack makes the endpoint available to the agent through a chat&lt;br&gt;
skill that gives strict instructions: use initial_context to discover&lt;br&gt;
the schema, schema_explorer to get the details about the fields,&lt;br&gt;
groq_query to retrieve the documents — and always base your answers&lt;br&gt;
&lt;strong&gt;on what the tools have returned, not on the training data&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agent serves as a comprehensive discovery guide: it first asks for your name and pronouns, then learns about the platforms you use and your preferences before creating a series of recommendations across the network—from games to developers to related games, then to characters, and finally to your history.&lt;/p&gt;
&lt;h2&gt;
  
  
  The agent in action
&lt;/h2&gt;

&lt;p&gt;What follows is an actual session: after the user names two games they&lt;br&gt;
loved, watch what happens.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Demo:&lt;/strong&gt; I loved &lt;em&gt;We Are OFK&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&amp;gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;QueerCade:&lt;/strong&gt; That helps a lot, Demo! Your best next game is&lt;br&gt;
&lt;strong&gt;Goodbye Volcano High&lt;/strong&gt; — like &lt;em&gt;We Are OFK&lt;/em&gt;, it follows young&lt;br&gt;
musicians navigating romance, friendship, and creative ambition. The&lt;br&gt;
protagonist, Fang, uses they/them pronouns.&lt;br&gt;&lt;br&gt;
&amp;gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Demo:&lt;/strong&gt; Also played and loved that.&lt;br&gt;&lt;br&gt;
&amp;gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;QueerCade:&lt;/strong&gt; You've already played the two closest matches —&lt;br&gt;
excellent taste. 🌈 My pick for you: &lt;strong&gt;Afterlove EP&lt;/strong&gt;. You play Rama,&lt;br&gt;
a young musician in modern Jakarta navigating grief and relationships&lt;br&gt;
— your choices branch the story. Or &lt;strong&gt;Stray Gods&lt;/strong&gt;, where your choices&lt;br&gt;
literally shape the musical numbers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is no result from a keyword search like that. The agent traced the&lt;br&gt;
lineage from &lt;strong&gt;representation through theme to developer and then to&lt;br&gt;
character identity&lt;/strong&gt; across the relevant documents. After exhausting the&lt;br&gt;
two most similar entries, it moved along a different branch of the graph&lt;br&gt;
rather than repeating the same process. In a previous part of the same&lt;br&gt;
session, it also knew when &lt;em&gt;not&lt;/em&gt; to overstate: when asked about a&lt;br&gt;
blockbuster's queer representation, it noted that the dataset did not&lt;br&gt;
specify it instead of making up information.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why this only works because the content is structured
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The recommendations do not focus on text similarity but instead follow&lt;br&gt;
references (for example, the developer of a game → the other games&lt;br&gt;
from that studio → the characters in those games).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The agent gives a reason for each selection—shared developers, shared&lt;br&gt;
themes, and shared representation—since it treats these relationships&lt;br&gt;
as first-class data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The editorial status (imported → under Review → approved → featured)&lt;br&gt;
indicates that the agent will always recommend only those games which&lt;br&gt;
humans have curated.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Agent: Superhuman GO pack → Sanity Context MCP endpoint (above)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The dataset is also used to power the Path Two app: &lt;a href="https://dev.to/mpmike/queercade-part-2-vibe-code-something-strange-an-arcade-of-queer-games-on-sanity-5c2c"&gt;Path 2: Something Strange&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://queercade.mikedemo.dev/emoji" rel="noopener noreferrer"&gt;Emoji Game Oracle&lt;/a&gt; (site discovery toy)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Code: &lt;a href="https://github.com/Mike-Demo/queer-game-vault" rel="noopener noreferrer"&gt;Queer Game Vault on GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Demo:
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://queercade.mikedemo.dev/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fqueercade.mikedemo.dev%2Fog-image.png" height="427" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://queercade.mikedemo.dev/" rel="noopener noreferrer" class="c-link"&gt;
            QueerCade — a curated arcade of games
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Hand-picked games with LGBTQ+ characters and stories: featured picks, curated collections, and a library you can track.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fqueercade.mikedemo.dev%2Ffavicon.png" width="64" height="64"&gt;
          queercade.mikedemo.dev
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/B8mKqX_jpf4" width="710" height="399"&gt;
  &lt;/iframe&gt;


&lt;p&gt;&lt;strong&gt;Sanity Project Details: Project ID: tzh8tziu&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I tried to use the knowledge base, but it had a limit on the number of documents. I contacted Sanity support and Discord support, and unfortunately, using the knowledge base MCP wasn't possible, which is why I connected to the standard dataset MCP instead.&lt;/p&gt;

&lt;p&gt;GitHUb Gist Below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;h2&gt;
  
  
  On Instagram
&lt;/h2&gt;


&lt;div class="instagram-position"&gt;
  &lt;blockquote class="instagram-media"&gt;
    &lt;div&gt;
      &lt;a href="https://www.instagram.com/reel/Dd9gqTvkc5A/" rel="noopener noreferrer"&gt;
        View this post on Instagram
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/blockquote&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  On X
&lt;/h2&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-2105372152773943343-930" src="https://platform.twitter.com/embed/Tweet.html?id=2105372152773943343"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-2105372152773943343-930');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=2105372152773943343&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspired by
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://x.com/gaymingmag" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpbs.twimg.com%2Fprofile_images%2F2086392458733146112%2FSMAlOhUg_200x200.jpg" height="200" class="m-0" width="200"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://x.com/gaymingmag" rel="noopener noreferrer" class="c-link"&gt;
            Gayming Magazine (@gaymingmag) / X
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            The home of queer geek culture 🏳️‍⚧️🏳️‍🌈🎮🕹️

Using this platform to celebrate LGBTQ+ excellence in an act of rebellion against its owner. 💪
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fx.com%2Ffavicon.ico" width="32" height="32"&gt;
          x.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  AI Disclosure
&lt;/h2&gt;

&lt;p&gt;AI assistance for this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Superhuman GO for MCP agent testing&lt;/li&gt;
&lt;li&gt;Microsoft Copilot for idea planning&lt;/li&gt;
&lt;li&gt;GitHub Copilot and Lovable for code&lt;/li&gt;
&lt;li&gt;Grammarly for editing review, with human edits&lt;/li&gt;
&lt;li&gt;Balsamiq AI for wireframe layouts&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>sanitychallenge</category>
      <category>sanity</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
