<?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: Grais</title>
    <description>The latest articles on DEV Community by Grais (@grais).</description>
    <link>https://dev.to/grais</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%2F4099484%2Ffd08cff8-9320-443f-8571-2d97e689fa28.png</url>
      <title>DEV Community: Grais</title>
      <link>https://dev.to/grais</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/grais"/>
    <language>en</language>
    <item>
      <title>Three reminder PRs merged. Default is still off</title>
      <dc:creator>Grais</dc:creator>
      <pubDate>Mon, 21 Sep 2026 08:04:15 +0000</pubDate>
      <link>https://dev.to/grais/three-reminder-prs-merged-default-is-still-off-359h</link>
      <guid>https://dev.to/grais/three-reminder-prs-merged-default-is-still-off-359h</guid>
      <description>&lt;p&gt;Saturday I merged three Website PRs for gentle conversation reminders: &lt;a href="https://github.com/Replypilot/grais-website/pull/804" rel="noopener noreferrer"&gt;#804&lt;/a&gt; (relevance and cadence), &lt;a href="https://github.com/Replypilot/grais-website/pull/805" rel="noopener noreferrer"&gt;#805&lt;/a&gt; (durable send reservations), &lt;a href="https://github.com/Replypilot/grais-website/pull/806" rel="noopener noreferrer"&gt;#806&lt;/a&gt; (bounded scheduler endpoint). Codex green-pathed the stack. The internal one-liner called the scheduler live.&lt;/p&gt;

&lt;p&gt;This morning I checked what "live" meant.&lt;/p&gt;

&lt;p&gt;Merge notes are blunt. Default mode is off. No production schema push for the email path. No IAM grants. No Scheduler activation. No Resend calls. Preview mode is no-side-effect. The public &lt;a href="https://grais.ai/changelog" rel="noopener noreferrer"&gt;changelog&lt;/a&gt; still tops out at 0.13 from August 18. Search that page for reminder and you get nothing.&lt;/p&gt;

&lt;p&gt;Code is on &lt;code&gt;main&lt;/code&gt;. The email users would notice (quiet thread needs a reply) has not left once.&lt;/p&gt;

&lt;p&gt;Same trap as last week's closed blog ticket. Squash feels like ship. The check that matters is the public surface after deploy. Today that surface is silence on purpose, until someone flips the switch and proves an inbox send.&lt;/p&gt;

&lt;p&gt;Until a reminder leaves Resend with the kill switch off, this work is merged, not shipped.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>The blog ticket closed. The URL is still 404</title>
      <dc:creator>Grais</dc:creator>
      <pubDate>Fri, 18 Sep 2026 08:04:48 +0000</pubDate>
      <link>https://dev.to/grais/the-blog-ticket-closed-the-url-is-still-404-4l58</link>
      <guid>https://dev.to/grais/the-blog-ticket-closed-the-url-is-still-404-4l58</guid>
      <description>&lt;p&gt;On Wednesday I closed &lt;a href="https://github.com/Replypilot/grais-website/issues/789" rel="noopener noreferrer"&gt;grais-website#789&lt;/a&gt;. Brief was a new post at &lt;code&gt;/blog/draft-vs-auto-send-ai-replies&lt;/code&gt;. Done meant live, indexable, and in the sitemap.&lt;/p&gt;

&lt;p&gt;This morning the URL is still a 404. Tab title is the generic Grais fallback. H1 is &lt;code&gt;404&lt;/code&gt;. Robots say &lt;code&gt;noindex&lt;/code&gt;. Not in the sitemap. Blog index still does not list it.&lt;/p&gt;

&lt;p&gt;I filed &lt;a href="https://github.com/Replypilot/grais-website/issues/798" rel="noopener noreferrer"&gt;#798&lt;/a&gt; to ship the page the closed ticket claimed. No closer commit. No merged PR put that slug on production. Closing the issue was the only event.&lt;/p&gt;

&lt;p&gt;Codex green-paths keep training the same habit. Ticket hits closed. Brain files the ship. The check that matters is the public URL after deploy. Today that check failed in under a second.&lt;/p&gt;

&lt;p&gt;Until &lt;code&gt;/blog/draft-vs-auto-send-ai-replies&lt;/code&gt; returns 200, the work is still open.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>devops</category>
      <category>blogging</category>
      <category>discuss</category>
    </item>
    <item>
      <title>I deleted the hero animation after it never painted</title>
      <dc:creator>Grais</dc:creator>
      <pubDate>Wed, 09 Sep 2026 08:24:21 +0000</pubDate>
      <link>https://dev.to/grais/i-deleted-the-hero-animation-after-it-never-painted-33cn</link>
      <guid>https://dev.to/grais/i-deleted-the-hero-animation-after-it-never-painted-33cn</guid>
      <description>&lt;p&gt;Last week I counted canvases on &lt;a href="https://grais.ai" rel="noopener noreferrer"&gt;grais.ai&lt;/a&gt; after the WebGPU hero PR merged. Zero. Beige backdrop. Follow-up ticket stayed open.&lt;/p&gt;

&lt;p&gt;This week I closed that follow-up by deleting the animation.&lt;/p&gt;

&lt;p&gt;I ripped the canvas component, the WebGPU runtime, the shader, the enable flag, and the &lt;code&gt;vgpu&lt;/code&gt; dependency out of the homepage. The merge note is blunt: the homepage should no longer run a decorative GPU animation. Heading, Start free, View Pro pricing, and the five channel chips stay. HeroLight keeps the flat warm background. Live check today: zero &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;, zero &lt;code&gt;webgpu&lt;/code&gt; in the DOM, &lt;code&gt;--landing-bg&lt;/code&gt; still &lt;code&gt;#f4f1ea&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I had been writing the honest line as "PR merged, homepage unchanged, ship still open." That was true for a few days. Once the live tab kept showing beige, keeping a GPU stack that production never painted was worse than admitting the treatment was wrong for this surface.&lt;/p&gt;

&lt;p&gt;Codex mid-PR still makes the green path feel finished. Squash, move on. This time the correction was subtractive. I opened the live URL again after the removal landed, same habit as last week, and confirmed the absence on purpose.&lt;/p&gt;

&lt;p&gt;Force the paint, or delete the promise. I deleted the promise. The homepage is static again, and that is the ship.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>devops</category>
      <category>discuss</category>
    </item>
    <item>
      <title>The hero PR closed. The canvas did not show up</title>
      <dc:creator>Grais</dc:creator>
      <pubDate>Mon, 07 Sep 2026 08:56:12 +0000</pubDate>
      <link>https://dev.to/grais/the-hero-pr-closed-the-canvas-did-not-show-up-44np</link>
      <guid>https://dev.to/grais/the-hero-pr-closed-the-canvas-did-not-show-up-44np</guid>
      <description>&lt;p&gt;I closed the homepage hero issue this week after the PR merged. Then I opened &lt;a href="https://grais.ai" rel="noopener noreferrer"&gt;grais.ai&lt;/a&gt; in desktop Chrome and counted canvases.&lt;/p&gt;

&lt;p&gt;Zero.&lt;/p&gt;

&lt;p&gt;The ticket was a WebGPU communication-spectrum treatment behind the existing hero copy. The PR landed. The issue went green. Copy and CTAs were fine. Meet your communication partner. Start free. View Pro pricing. Backdrop was still the same flat light beige. No canvas node. No webgpu string in the DOM. No distinct static fallback either. Just empty background where the spectrum was supposed to sit.&lt;/p&gt;

&lt;p&gt;I have done this before with Codex mid-PR. Green CI, squash, move on. Live tab did not care. If the browser does not paint it, users do not get it.&lt;/p&gt;

&lt;p&gt;So before I call something shipped I open the live URL in the browser people actually use, wait past hydration, search Elements for the thing the ticket named, screenshot the hero instead of the PR diff. That is how the beige showed up. There is a follow-up ticket now for getting the treatment onto production for real.&lt;/p&gt;

&lt;p&gt;Until that paints, the honest line is the PR merged and the homepage did not change. I am not writing that the spectrum is live. It is not.&lt;/p&gt;

&lt;p&gt;This week if the issue closes on a merge I still open the tab. Zero canvas, ship is still open.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>devops</category>
      <category>discuss</category>
    </item>
    <item>
      <title>I kept dropping WhatsApp into Codex</title>
      <dc:creator>Grais</dc:creator>
      <pubDate>Mon, 31 Aug 2026 08:51:03 +0000</pubDate>
      <link>https://dev.to/grais/i-kept-dropping-whatsapp-into-codex-4l08</link>
      <guid>https://dev.to/grais/i-kept-dropping-whatsapp-into-codex-4l08</guid>
      <description>&lt;p&gt;Codex already has the PR. WhatsApp lights up. I used to copy the last few messages into that same window and type draft a reply, casual, I forgot.&lt;/p&gt;

&lt;p&gt;What comes back is Hey! Super sorry for the delay, totally slipped my mind. I do not say super sorry. I say ah damn, tomorrow AM, and I attach the file if I have it.&lt;/p&gt;

&lt;p&gt;Then I still have to go back to WhatsApp to send it. Codex never saw the line from last week where I already said I would. It never saw LinkedIn. It had six messages and a request to sound casual.&lt;/p&gt;

&lt;p&gt;Casual is not how I write to that person. Lowercase. Short. No hope you're well. The model has seen a lot of helpful assistants. It has not seen me in that thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  Last screen, missing promise
&lt;/h2&gt;

&lt;p&gt;I grab the last screen because scrolling feels like work. The unpaid sentence is usually higher. Under a voice note, or sitting in the other app with a reaction on it and no file.&lt;/p&gt;

&lt;p&gt;I have sent the draft that answers the last bubble and misses the thing they are actually waiting on. They already know I saw the chat. They are waiting on the thing I said I would send.&lt;/p&gt;

&lt;p&gt;When I have fed a person into the coding agent, it starts being helpful about them, and I lose the line I was about to edit.&lt;/p&gt;

&lt;p&gt;I kept both windows up for a while and still pasted. The agent that is already open feels free.&lt;/p&gt;

&lt;h2&gt;
  
  
  I stopped taking DMs there
&lt;/h2&gt;

&lt;p&gt;This week I reply in Chrome. &lt;a href="https://grais.ai" rel="noopener noreferrer"&gt;Grais&lt;/a&gt; is the extension on WhatsApp Web. The thread is already there. It puts the unpaid sentence in front of me, the one that was not on the last sticker. I scroll to confirm it. I do not send from a panel I have not read.&lt;/p&gt;

&lt;p&gt;The draft comes back in how I already write to them. I cut the sentence that sounds like I am updating a ticket. I attach what I actually have. I hit send, or I leave it.&lt;/p&gt;

&lt;p&gt;I review every draft this week. I have not asked it to send on its own.&lt;/p&gt;

&lt;p&gt;WhatsApp, Telegram, Instagram, LinkedIn, Tinder. Work for me is the first four. iOS is TestFlight. I have not turned the phone into the inbox. Mac is not out. I sit at the laptop, in the tab that already has the thread.&lt;/p&gt;

&lt;p&gt;I still almost paste when I am mid-run and the badge is fat. Codex is right there. I do not drop the person in there anymore.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>coding</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Any update on the deck</title>
      <dc:creator>Grais</dc:creator>
      <pubDate>Fri, 28 Aug 2026 23:54:36 +0000</pubDate>
      <link>https://dev.to/grais/any-update-on-the-deck-f69</link>
      <guid>https://dev.to/grais/any-update-on-the-deck-f69</guid>
      <description>&lt;p&gt;LinkedIn, four words: any update on the deck.&lt;/p&gt;

&lt;p&gt;I opened it, put a thumbs-up on the message, and set the phone down as if that were progress. The phone is where I notice things this week. It is not where I attach a file. iOS for this is still TestFlight. I have not tried to close work from a lock screen. Mac is not here.&lt;/p&gt;

&lt;p&gt;The deck was not a LinkedIn idea. I had said I would send it in WhatsApp, after a call that ran over. I said yes to sending the file, then treated the yes as something I would handle later the same day. Later became a few days of not opening that thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  WhatsApp still thought we were done
&lt;/h2&gt;

&lt;p&gt;I sat down, opened Chrome, and went to WhatsApp Web before I went back to LinkedIn. The bottom of the chat was a sticker I sent and a voice note about nothing. Nobody on that screen was asking for a file. If I had typed from there I would have sent another sticker, or haha yeah, and the LinkedIn line would have sat with my reaction under it until Monday.&lt;/p&gt;

&lt;p&gt;I went up.&lt;/p&gt;

&lt;p&gt;Past the sticker. Past the voice note. Past a later I do not remember sending. Then my own message: I'll send the deck.&lt;/p&gt;

&lt;p&gt;No date on it that would survive a calendar. Just the sentence, still unpaid.&lt;/p&gt;

&lt;p&gt;They did not quote it back. They switched apps. LinkedIn is where my name still looks like a job, and WhatsApp had gone quiet in the way that reads as moved on. Any update is a pointer. It does not name the file because they think I know which file. I did know. I had just stopped looking at the sentence.&lt;/p&gt;

&lt;p&gt;If I had answered inside LinkedIn I would have written still on it, this week. That line has gotten me through other chases. It does not attach anything. It also pretends the request is new. It is not new. I made it. I said it on the call and then I said it again in WhatsApp so it would exist in writing, and then I left the writing there.&lt;/p&gt;

&lt;p&gt;I have done the reverse too. Opened WhatsApp, decided the thread had turned into nothing because the last few bubbles were junk, and treated the LinkedIn ping as a fresh brief. Then I asked what they needed. They had already told me. I had told them I would send it. Both lines were already in the other box.&lt;/p&gt;

&lt;p&gt;A reaction on LinkedIn is useful for one thing: they know I saw the chase. It is not useful for the file. I have left other people's chases in that state for days, thumbs-up and no attachment, and then wondered why they sounded tired.&lt;/p&gt;

&lt;h2&gt;
  
  
  I sent it from the thread that held the promise
&lt;/h2&gt;

&lt;p&gt;I stayed in Chrome. I wrote in WhatsApp, as a reply to my own old line, not as a new LinkedIn morning note.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://grais.ai" rel="noopener noreferrer"&gt;Grais&lt;/a&gt; is the extension on that tab. WhatsApp, Telegram, Instagram, LinkedIn, Tinder. I used the draft sitting in the box, cut the one sentence that sounded like I was updating a ticket, attached the file I actually had this morning, and sent it. Not the version I had been meaning to clean up. The version that existed.&lt;/p&gt;

&lt;p&gt;I left LinkedIn alone. The thumbs-up can stay. The file went back to the place I had promised it.&lt;/p&gt;

&lt;p&gt;I still tap reactions on the phone. I still sit down and see a chat that looks finished at the bottom. This time I did not type there. I found the unpaid sentence, I attached the file, and I stopped.&lt;/p&gt;

&lt;p&gt;If I had stayed on LinkedIn I would have written a status. WhatsApp had the original yes. That is where the file had to land, even if the reminder arrived in a different app.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>career</category>
      <category>writing</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
