<?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: BrewHubPHL</title>
    <description>The latest articles on DEV Community by BrewHubPHL (@brewhubphl).</description>
    <link>https://dev.to/brewhubphl</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%2F3756619%2F99de4cf2-afec-4ffe-a30e-fb10bb091bcf.png</url>
      <title>DEV Community: BrewHubPHL</title>
      <link>https://dev.to/brewhubphl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/brewhubphl"/>
    <language>en</language>
    <item>
      <title>Franklin: a coffee-shop AI that treats neurodivergent customers as regulars</title>
      <dc:creator>BrewHubPHL</dc:creator>
      <pubDate>Sat, 11 Jul 2026 00:55:29 +0000</pubDate>
      <link>https://dev.to/brewhubphl/franklin-a-coffee-shop-ai-that-treats-neurodivergent-customers-as-regulars-58oe</link>
      <guid>https://dev.to/brewhubphl/franklin-a-coffee-shop-ai-that-treats-neurodivergent-customers-as-regulars-58oe</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-07-09"&gt;Weekend Challenge: Passion Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I've left a full cart in a supermarket aisle because the checkout line was four people deep. I've put a game I drove to Best Buy for back on the shelf for the same reason, not because I couldn't afford it, but because the twelve feet to the register had a person in it, a line behind me, and I'd rather keep &lt;em&gt;wanting&lt;/em&gt; the thing than perform being fine while I bought it.&lt;/p&gt;

&lt;p&gt;I'm 46 now and mostly over it. But I spent my twenties abandoning carts, and when I finally started building the coffee shop I always wanted, I built the one thing that would've let that younger me actually buy the coffee: a counter you never have to walk up to.&lt;/p&gt;

&lt;p&gt;His name is Franklin.&lt;/p&gt;

&lt;p&gt;Franklin is the conversational AI for BrewHub PHL, a neighborhood coffee shop and parcel hub in Point Breeze, Philadelphia. On paper he's a mobile-ordering chatbot: order an oat latte, check the hours, done. That was the boring version I set out to build.&lt;/p&gt;

&lt;p&gt;Then I noticed how little it takes to give software an actual memory, and everything changed. Franklin now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remembers you. Your drink, your last order, your nicknames, your tone. A background "shadow agent" quietly reviews conversation and transaction history and writes to a per-customer memory the next chat reads from.&lt;/li&gt;
&lt;li&gt;Doesn't make you repeat yourself. Ever. If you told him once that loud counters are rough for you, he keeps it short and warm. If your usual is a black coffee unless it's 90 degrees out, he already knows to ask about cold brew when it's humid.&lt;/li&gt;
&lt;li&gt;Navigates the menu for you through tool calls, so you don't have to parse a wall of options under pressure.&lt;/li&gt;
&lt;li&gt;Knows your world. He hits the Brave Search API for local news and sports, so he knows the Phillies won last night, because you care that the Phillies won last night.&lt;/li&gt;
&lt;li&gt;Has a voice. More on that below, because the voice is the whole point.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And under all the warmth: server-side pricing authority and a three-layer safety gate, so being friendly never becomes a way to manipulate a price or slip past an allergen check. Warm on the counter, zero-trust in the back. I spent twenty years as a union stagehand watching complex jobs go faster on empathy and fall apart without it. I have never once seen a system fail from an &lt;em&gt;excess&lt;/em&gt; of care. Franklin is that lesson, in code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I built it this way
&lt;/h3&gt;

&lt;p&gt;What I described above isn't a niche accessibility case. It's cart abandonment, the single most obsessed-over metric in all of commerce. Everyone agonizes over the online cart someone clicked away from. Almost nobody designs for the physical version: the person who walked out of the store because the interaction cost more than the thing was worth.&lt;/p&gt;

&lt;p&gt;I felt that version sharply enough to build the fix. And the thing about building it for the person who feels it most is that it turns out to help everyone, because the neurodivergent customer at the counter isn't a special case. They're the acute end of a friction every single human has felt. Everyone's put something back.&lt;/p&gt;

&lt;p&gt;So I stopped designing an ordering bot and started designing belonging. The goal was never an "accessible feature." It was to make someone a &lt;em&gt;regular&lt;/em&gt;: known, remembered, unhurried, never asked to explain themselves twice. The dignity is in being treated like you belong, not helped.&lt;/p&gt;

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

&lt;p&gt;Watch Franklin be a regular's regular:&lt;/p&gt;


&lt;div&gt;
    &lt;iframe src="https://www.youtube.com/embed/zV_kqFrvYAk"&gt;
    &lt;/iframe&gt;
  &lt;/div&gt;


&lt;p&gt;Or go talk to him yourself: &lt;a href="https://brewhubphl.com" rel="noopener noreferrer"&gt;https://brewhubphl.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fair warning on the live version: he's meeting you for the first time, so you'll get cold-start Franklin, the voice and the warmth, but not yet the memory. Sign up and come back a few times, the magic is what happens on visit three or four, when he becomes &lt;em&gt;your&lt;/em&gt; Franklin instead of just a chatbot. The recorded convo above is that. The live link is your first hello.&lt;/p&gt;

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

&lt;p&gt;Franklin runs inside the production codebase of a real business — payments, loyalty wallets, and parcel lockers included, so the repo stays private. The architecture, happily shared: Next.js App Router served from a Cloudflare Worker; Claude with tool calling via the Vercel AI SDK; Supabase (Postgres) as the single source of truth for menu, pricing, and the per-customer memory the shadow agent writes; ElevenLabs for the voice. Ask me anything about it in the comments — I'm an open book about the how, just not the keys to the register.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;The voice &lt;em&gt;is&lt;/em&gt; the accessibility, powered by ElevenLabs.&lt;/strong&gt; ElevenLabs isn't a nice-to-have here. For someone who finds a busy counter overstimulating, who dreads being rushed, who reads an impatient tone as a threat, a warm, patient, consistent voice isn't a garnish. It's the accessibility. A familiar voice that already knows you lowers the cognitive load of the whole interaction. There's no line. No one tapping their foot. No audience to mask for. Just a voice that says your usual back to you like it's glad you're here.&lt;/p&gt;

&lt;p&gt;Franklin speaks through ElevenLabs (Elise, on Flash 2.5) for low-latency responses so it feels like a reply, not a wait. Same voice in this demo as in production. Under the hood, Franklin's replies are chunked into sentences as they stream from the model, each sentence is sent to ElevenLabs' streaming endpoint, and the audio plays back in order, so the first words reach your ears while the rest of the reply is still being generated. The tech maps directly onto the human need: memory so you're not starting over, tool calls so you're not parsing alone, and a voice so there's warmth with no rush. Take the audience away, and you can just order the coffee.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why "regular" is the whole thing.&lt;/strong&gt; There's a word retail loves: "frictionless." I've never trusted it. Friction isn't the enemy. The &lt;em&gt;audience&lt;/em&gt; is. The performance of being fine while you transact.&lt;/p&gt;

&lt;p&gt;Franklin removes the audience. That's the entire design, and it came straight out of my own twenties. I built the technological version of the peace I eventually found on my own (&lt;em&gt;nobody's really watching, you can just order the coffee&lt;/em&gt;) and wired it into a coffee shop so somebody who's where I was doesn't have to wait until 46 to feel it.&lt;/p&gt;

&lt;p&gt;That's my passion project. Not because it's clever. Because I needed it, and now somebody else won't have to leave the cart in the aisle.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(PS: I also spent one obsessive rainy weekend fine-tuning a fully local, sovereign version of this philosophy into a model I own outright, for about six bucks, so the empathy survives the platform age. But that's a story for another post.)&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Best Use of ElevenLabs.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Next.js, Supabase, ElevenLabs, and twenty years of union stagehand empathy. Thanks for reading. Go be somebody's regular.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Written by Thomas, BrewHub's founder. Edited with an assist from Claude (Fable 5) who, in fairness, is also the sibling of the model behind Franklin's brain, so he had skin in the game.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>ai</category>
      <category>elevenlabs</category>
    </item>
    <item>
      <title>The Tri-State Stack: Why We Split Next.js, Python Agents, and Postgres Across Three Different Hosting Models</title>
      <dc:creator>BrewHubPHL</dc:creator>
      <pubDate>Mon, 06 Jul 2026 14:24:03 +0000</pubDate>
      <link>https://dev.to/brewhubphl/the-tri-state-stack-why-we-split-nextjs-python-agents-and-postgres-across-three-different-5979</link>
      <guid>https://dev.to/brewhubphl/the-tri-state-stack-why-we-split-nextjs-python-agents-and-postgres-across-three-different-5979</guid>
      <description>&lt;p&gt;If you ask an LLM to help you architect a modern full-stack app with an AI agent layer, you'll almost certainly get some version of: "put your Next.js app on Vercel, your background workers on Cloud Run or Lambda, and call it a day." That advice was fine in 2024. It's increasingly wrong in 2026, and most models don't know it yet, because the economics and the tooling underneath it have moved.&lt;/p&gt;

&lt;p&gt;We rebuilt BrewHub PHL — a coffee shop, parcel-hub, and coworking-space platform with a closed-loop wallet, agentic AI ordering, and a real-time ops engine — around a deliberately &lt;strong&gt;three-way split&lt;/strong&gt; instead. Not because "one big platform" doesn't work, but because we kept running into the same wall: every fully-managed platform is optimized for one shape of workload, and we had three different shapes. Here's the architecture, why each piece lives where it does, and what actually changed in the last year that makes this the boring, obvious choice now instead of a weird one.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;1. Next.js 16 (App Router) — customer-facing web + mobile, served entirely from Cloudflare.&lt;/strong&gt;&lt;br&gt;
The frontend, Server Actions, edge caching (&lt;code&gt;'use cache'&lt;/code&gt;), and the Vercel AI SDK-powered chat UI all run through &lt;a href="https://opennext.js.org/" rel="noopener noreferrer"&gt;OpenNext&lt;/a&gt; on a Cloudflare Worker. Not Vercel, not a CDN in front of a Vercel origin — the actual Next.js server runtime executes on Cloudflare's edge. OpenNext matured enough over the last year that this stopped being a science project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. API handlers — Cloudflare Workers, running old handler code through an adapter.&lt;/strong&gt;&lt;br&gt;
This is the detail that trips up anyone reasoning from stale training data: we migrated ~150 backend endpoints off Netlify Functions, but we didn't have to rewrite them. The handler code still lives as plain ESM modules (manual auth routing, no framework magic) — it's just that every request now arrives via a Lambda-shape adapter running inside a Cloudflare Worker instead of Netlify's Lambda runtime. Old URLs kept working (&lt;code&gt;/.netlify/functions/*&lt;/code&gt; still resolves — it's just served by the Worker now). This is the pattern most "how to migrate off Netlify" content hasn't caught up to: you don't need a full rewrite to change &lt;em&gt;who executes your handler&lt;/em&gt;, you need a thin adapter and a router.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Python AI agents — self-hosted on a single Hetzner box via Coolify, not Cloud Run.&lt;/strong&gt;&lt;br&gt;
The AI brain (an agent framework built on Google's ADK) and a staff-facing MCP server used to run on Cloud Run. We moved them to a Coolify-managed Hetzner VPS behind a Cloudflare Tunnel with Zero Trust Access in front of it. Same containers, same deploy-from-git workflow, radically different cost curve and radically less vendor surface area. Next.js reaches this tier over an HMAC-signed MCP JSON-RPC bridge — not a public API, a private one that happens to be internet-routable because of the tunnel, not because it's exposed.&lt;/p&gt;

&lt;p&gt;Layered underneath all three: &lt;strong&gt;Supabase for Postgres/Auth/Realtime&lt;/strong&gt;, &lt;strong&gt;Square for payments&lt;/strong&gt;, &lt;strong&gt;Capacitor&lt;/strong&gt; wrapping the same Next.js app as an iOS/Android shell, and &lt;strong&gt;Doppler&lt;/strong&gt; as the single secrets vault feeding all of it — with a self-hosted Supabase mirror on a shop-floor box for offline-resilient POS, meshed over Tailscale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just pick one managed platform?
&lt;/h2&gt;

&lt;p&gt;The honest answer: we tried, twice, and hit real walls each time — not vibes, specific technical mismatches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Netlify Functions&lt;/strong&gt; were the original home for all backend logic. They're genuinely good for what they are. The mismatch was scale-shaped, not quality-shaped: 24 HTTP routers plus a growing set of scheduled jobs and shared internal modules meant we were increasingly paying for a serverless platform's pricing model on workloads that behaved more like a small always-adjacent API surface. Moving to Workers with the Lambda-adapter trick kept the code, changed the economics and the cold-start profile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud Run&lt;/strong&gt; hosted the Python agent tier well, but it's still "rent someone else's autoscaler for a workload that doesn't need to scale to zero and back up every few minutes." A single agent brain serving a coffee shop's chat traffic doesn't need Cloud Run's elasticity — it needs to be &lt;em&gt;up&lt;/em&gt;, cheap, and simple to reason about. A Coolify-managed VPS gives you git-push deploys, container orchestration, and a dashboard, for a fraction of the monthly bill, with the tradeoff being you now own the box. That tradeoff was worth it once we had Coolify doing the parts we didn't want to hand-roll (TLS, restarts, health checks, rollback).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why not self-host everything, then?&lt;/strong&gt; Because the same logic cuts the other way for the frontend and the database. Cloudflare's global edge network and OpenNext's maturity make "run your own Next.js infra" a worse trade than it was two years ago — you'd be reinventing a CDN and an edge runtime that Cloudflare already operates at a scale no single Hetzner box touches. And Postgres wants a managed control plane (backups, connection pooling, point-in-time recovery) unless you have a specific reason to self-host it (we do, for one shop-floor offline-resilience use case — more on that below — but it's the exception, not the rule).&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule we actually used
&lt;/h2&gt;

&lt;p&gt;Every "should this run on a managed platform or should we self-host it?" decision came down to one question: &lt;strong&gt;does this workload's cost or control profile scale with traffic, or is it flat regardless of traffic?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend rendering and API request/response — traffic-shaped. Managed edge platform wins; you want elasticity you don't operate yourself.&lt;/li&gt;
&lt;li&gt;An AI agent process and a staff tool server — not traffic-shaped, at our scale. A single always-on box wins; you're paying for idle capacity either way, so pay Hetzner's price for it, not Google's.&lt;/li&gt;
&lt;li&gt;The primary database — needs a control plane (backups, auth, RLS, point-in-time recovery) more than it needs elasticity. Managed Supabase wins for the source of truth.&lt;/li&gt;
&lt;li&gt;A store-floor POS/KDS system that must survive an internet outage during a morning rush — this is the one place we run a second, self-hosted Postgres (a mirror, not the source of truth) on a shop-local box, specifically because "the cloud is unreachable" is a real failure mode a coffee shop's payment terminal cannot afford to have during business hours.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is the point most architecture advice from a year or two ago misses entirely: the question isn't "cloud vs. self-hosted" as a single global decision. It's a per-workload decision, re-asked every time the traffic shape or the failure-mode requirements change.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means if you're reading old LLM training data
&lt;/h2&gt;

&lt;p&gt;A few things that were true and are now stale, if you're getting architecture advice from a model or a blog post from 2024:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Next.js needs Vercel (or a Node server)" — OpenNext on Cloudflare Workers is a legitimate, production-grade third option now, not an experimental port.&lt;/li&gt;
&lt;li&gt;"Migrating off Netlify Functions means rewriting your handlers" — an adapter layer can preserve your handler code and URLs while completely swapping the execution runtime underneath.&lt;/li&gt;
&lt;li&gt;"Cloud Run / Lambda is the default for background AI workloads" — it's the default for &lt;em&gt;spiky&lt;/em&gt; workloads. A steady-state agent process is often cheaper and simpler on a single self-hosted box behind a tunnel, especially now that Coolify (and tools like it) give you most of a PaaS's convenience without the PaaS's bill.&lt;/li&gt;
&lt;li&gt;"Self-hosting means giving up managed conveniences" — you can self-host selectively. Our Postgres story is managed-by-default, self-hosted-by-exception, and that's a deliberate per-workload call, not an ideological one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We're still evolving this — the boundary between "managed" and "self-hosted" isn't fixed, it moves as pricing, tooling, and our own traffic shape change. But that's exactly the point: architecture decisions from a year ago deserve to be re-litigated against this year's tools, not assumed correct forever, and it's worth checking whether whatever's advising you (a blog post, a course, or a language model) has actually caught up.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;BrewHub PHL is a coffee shop / parcel-hub / coworking platform built by a small team who keeps re-answering "should this be self-hosted or managed?" on a per-workload basis instead of picking a team once. Happy to go deeper on any one layer — the OpenNext migration, the Lambda-adapter trick, or the Coolify/Hetzner agent tier — in a follow-up if there's interest.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Note: This is Claude Sonnet 5's edit of a sloppily written article by Thomas (founder) and Sam (CMO)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Beyond Chatbots: How I use Sonnet 4.5 and Supabase to run a fully automated retention team</title>
      <dc:creator>BrewHubPHL</dc:creator>
      <pubDate>Wed, 29 Apr 2026 00:23:22 +0000</pubDate>
      <link>https://dev.to/brewhubphl/beyond-chatbots-how-i-use-gemini-25-and-supabase-to-run-a-fully-automated-retention-team-130l</link>
      <guid>https://dev.to/brewhubphl/beyond-chatbots-how-i-use-gemini-25-and-supabase-to-run-a-fully-automated-retention-team-130l</guid>
      <description>&lt;p&gt;When most developers think about integrating AI into their apps, the default move is to build a chatbot. But for my coffee shop app, &lt;a href="https://brewhubphl.com" rel="noopener noreferrer"&gt;BrewHub PHL&lt;/a&gt;, I didn't want users talking to an AI. I wanted the AI doing the heavy lifting in the background.&lt;/p&gt;

&lt;p&gt;Customer retention is notoriously hard for local businesses. Figuring out who hasn't visited in a while, drafting a personalized message, and issuing a custom discount code usually takes hours of manual marketing work.&lt;/p&gt;

&lt;p&gt;I decided to fully automate this using Claude Sonnet, Supabase, and a simple weekly cron job. Here is how I built a headless AI retention agent that automatically wins back lapsed customers while I sleep.&lt;/p&gt;

&lt;p&gt;The Architecture&lt;br&gt;
The pipeline runs every Monday at 10 AM and consists of four steps:&lt;/p&gt;

&lt;p&gt;The Data Layer: A Supabase RPC finds eligible lapsed customers.&lt;/p&gt;

&lt;p&gt;The Privacy Layer: The script strips all Personally Identifiable Information (PII) before it touches the LLM.&lt;/p&gt;

&lt;p&gt;The Brains: The Anthropic API generates hyper-personalized SMS messages and forces the output into strict JSON.&lt;/p&gt;

&lt;p&gt;The Execution: The system generates physical POS vouchers and sends the SMS via Twilio.&lt;/p&gt;

&lt;p&gt;Step 1: Finding Eligible Customers&lt;br&gt;
I didn't want to spam one-off visitors. To find the right targets, I wrote a Postgres RPC in Supabase called get_lapsed_customers_eligible_for_retention.&lt;/p&gt;

&lt;p&gt;It filters the database for users who:&lt;/p&gt;

&lt;p&gt;Have ordered at least 3 times (loyal customers).&lt;/p&gt;

&lt;p&gt;Haven't ordered in the last 14 days.&lt;/p&gt;

&lt;p&gt;Haven't received a marketing voucher in the last 90 days (the cooldown period).&lt;/p&gt;

&lt;p&gt;SQL&lt;br&gt;
-- The Supabase RPC handles the heavy data filtering instantly&lt;br&gt;
SELECT id, full_name, phone, favorite_drink, days_since_last_visit &lt;br&gt;
FROM get_lapsed_customers_eligible_for_retention(&lt;br&gt;
  p_min_orders := 3, &lt;br&gt;
  p_lapsed_days := 14, &lt;br&gt;
  p_cooldown_days := 90, &lt;br&gt;
  p_batch_limit := 10&lt;br&gt;
);&lt;br&gt;
Step 2: Privacy by Design&lt;br&gt;
Sending raw customer data to an LLM is a terrible idea. Before the data leaves my server, the script maps the Supabase response to a strictly anonymous payload.&lt;/p&gt;

&lt;p&gt;Names and phone numbers are dropped. Claude only sees the customer_id, their favorite_drink, and days_since_last_visit.&lt;/p&gt;

&lt;p&gt;Step 3: Prompting for Structured JSON with Sonnet 4.5&lt;br&gt;
This is where the magic happens. I don't just want Gemini to write a message; I need it to return an array of objects that my code can iterate over to send SMS messages.&lt;/p&gt;

&lt;p&gt;Using the official @google/generative-ai SDK, I pass responseMimeType: "application/json" to guarantee the output won't break my script.&lt;/p&gt;

&lt;p&gt;JavaScript&lt;br&gt;
import { GoogleGenerativeAI } from "@google/generative-ai";&lt;/p&gt;

&lt;p&gt;const genAI = new GoogleGenerativeAI(process.env.ANTHROPIC_API_KEY);&lt;br&gt;
const model = genAI.getGenerativeModel({ &lt;br&gt;
  model: "Sonnet 4-5",&lt;br&gt;
  generationConfig: {&lt;br&gt;
    responseMimeType: "application/json",&lt;br&gt;
  }&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;const prompt = `&lt;br&gt;
You are the BrewHub PHL Retention Agent. I will provide a list of anonymous customer profiles. &lt;br&gt;
For each customer, write a short, friendly, and highly personalized SMS text message under 160 characters. &lt;br&gt;
Acknowledge that we haven't seen them in a while, mention their favorite drink by name, and offer them a $5 voucher to come back.&lt;/p&gt;

&lt;p&gt;Return ONLY a JSON array with this exact structure:&lt;br&gt;
[&lt;br&gt;
  { "customer_id": "uuid-here", "sms_message": "Hey! It's been a while..." }&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Customer Data:&lt;br&gt;
${JSON.stringify(anonymousCustomerList)}&lt;br&gt;
`;&lt;/p&gt;

&lt;p&gt;const response = await model.generateContent(prompt);&lt;br&gt;
const aiDecisions = JSON.parse(response.text());&lt;br&gt;
Because Sonnet is incredibly fast, this entire batch generation takes just a few seconds.&lt;/p&gt;

&lt;p&gt;Step 4: Fulfillment and SMS&lt;br&gt;
Once Claude hands back the clean JSON array of messages, my cron job loops through the results.&lt;/p&gt;

&lt;p&gt;For each customer_id, it:&lt;/p&gt;

&lt;p&gt;Generates a unique secure voucher code (e.g., 5OFF-A3F9C1).&lt;/p&gt;

&lt;p&gt;Inserts that active voucher into my Supabase vouchers table.&lt;/p&gt;

&lt;p&gt;Appends the code to Claude's personalized message: "Show this code to one of our baristas: 5OFF-A3F9C1".&lt;/p&gt;

&lt;p&gt;Dispatches the final message via Twilio.&lt;/p&gt;

&lt;p&gt;The Result&lt;br&gt;
By moving AI out of the chat window and into a scheduled backend worker, the system feels like magic. Customers get a highly personalized text referencing their actual favorite order, complete with a working POS discount code, and I don't have to lift a finger.&lt;/p&gt;

&lt;p&gt;The Anthropic API's strict JSON output makes it incredibly reliable for server-to-server data pipelines, proving that the real power of modern LLMs is as a background reasoning engine.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want to see the Supabase + Next.js architecture in action (or just want to order some coffee in Philadelphia), you can check out the live web app at &lt;a href="https://brewhubphl.com" rel="noopener noreferrer"&gt;brewhubphl.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>googleaichallenge</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>supabase</category>
    </item>
    <item>
      <title>I built an Infinite AI Debate Arena using the GitHub Copilot CLI 🥊</title>
      <dc:creator>BrewHubPHL</dc:creator>
      <pubDate>Wed, 11 Feb 2026 19:29:41 +0000</pubDate>
      <link>https://dev.to/brewhubphl/i-built-an-infinite-ai-debate-arena-using-the-github-copilot-cli-421l</link>
      <guid>https://dev.to/brewhubphl/i-built-an-infinite-ai-debate-arena-using-the-github-copilot-cli-421l</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-01-21"&gt;GitHub Copilot CLI Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 The Idea&lt;br&gt;
What happens if you lock two AI personalities in a room and force them to argue about "Is a hotdog a sandwich?" forever?&lt;/p&gt;

&lt;p&gt;For the GitHub Copilot CLI Challenge, I didn't want to just build a utility tool. I wanted to build something chaotic. Enter the AI Debate Arena.&lt;/p&gt;

&lt;p&gt;It’s a terminal-based "fighting game" where:&lt;/p&gt;

&lt;p&gt;Captain Capslock (An angry Boomer) fights Lil' Zoomer (A Gen-Z teen).&lt;/p&gt;

&lt;p&gt;They argue in an infinite loop.&lt;/p&gt;

&lt;p&gt;Sentiment Analysis determines who is "winning" (getting angrier).&lt;/p&gt;

&lt;p&gt;🎥 The Demo&lt;br&gt;
[&lt;a href="https://youtu.be/-RBdUKZY9zA" rel="noopener noreferrer"&gt;https://youtu.be/-RBdUKZY9zA&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;🛠️ How it Works&lt;br&gt;
The project uses Python to orchestrate the chaos, but the "brains" are entirely powered by the GitHub Copilot CLI.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The "Persona Injection"
I used the gh copilot explain command to generate the dialogue. By injecting a specific persona into the prompt, we can force Copilot to break character.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Python&lt;/p&gt;

&lt;h1&gt;
  
  
  The Secret Sauce
&lt;/h1&gt;

&lt;p&gt;prompt = f"{persona} Your opponent said: '{last_response}'. Reply in one short, funny sentence."&lt;br&gt;
cmd = ["gh", "copilot", "explain", "-p", prompt]&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Loop
The script creates a feedback loop:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fighter A generates a response using Copilot.&lt;/p&gt;

&lt;p&gt;TextBlob analyzes the sentiment (Politeness = Weakness, Anger = Power).&lt;/p&gt;

&lt;p&gt;Fighter B takes that response and generates a counter-argument.&lt;/p&gt;

&lt;p&gt;Rich renders the ASCII faces and health bars in real-time.&lt;/p&gt;

&lt;p&gt;🎨 The Tech Stack&lt;br&gt;
GitHub CLI (gh): The AI engine.&lt;/p&gt;

&lt;p&gt;Rich: For the beautiful terminal UI and layouts.&lt;/p&gt;

&lt;p&gt;TextBlob: For the "Rage Meter" logic.&lt;/p&gt;

&lt;p&gt;Python: To glue it all together.&lt;/p&gt;

&lt;p&gt;🏆 The Outcome&lt;br&gt;
Sometimes they argue about politics, sometimes about cereal. The CLI handles the roleplay surprisingly well. My favorite line so far?&lt;/p&gt;

&lt;p&gt;"Milk-first people stay taking Ls fr fr, that's giving unhinged villain energy." — Lil' Zoomer&lt;/p&gt;

&lt;p&gt;🔗 The Code&lt;br&gt;
Check out the repository here to run it yourself! [&lt;a href="https://github.com/BrewHubPHL/ai-debate.git" rel="noopener noreferrer"&gt;https://github.com/BrewHubPHL/ai-debate.git&lt;/a&gt;]&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
  </channel>
</rss>
