<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[memolio: Build in Public]]></title><description><![CDATA[Weekly dev diary from the trenches of building an AI-powered personalised book product. Bugs, breakthroughs, and the honest reality of shipping solo.]]></description><link>https://blog.memolio.io/s/build-in-public</link><image><url>https://substackcdn.com/image/fetch/$s_!wkaj!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3178a0e8-8a6c-41d3-9a7b-602828a57b69_2316x2316.jpeg</url><title>memolio: Build in Public</title><link>https://blog.memolio.io/s/build-in-public</link></image><generator>Substack</generator><lastBuildDate>Sun, 12 Apr 2026 17:31:07 GMT</lastBuildDate><atom:link href="https://blog.memolio.io/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[The Egg Consultancy]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[memolio@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[memolio@substack.com]]></itunes:email><itunes:name><![CDATA[memolio]]></itunes:name></itunes:owner><itunes:author><![CDATA[memolio]]></itunes:author><googleplay:owner><![CDATA[memolio@substack.com]]></googleplay:owner><googleplay:email><![CDATA[memolio@substack.com]]></googleplay:email><googleplay:author><![CDATA[memolio]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The Ninety-Second Fix That Took Four Hours]]></title><description><![CDATA[Build in Public &#8212; Memolio, 10 April 2026]]></description><link>https://blog.memolio.io/p/the-ninety-second-fix-that-took-four</link><guid isPermaLink="false">https://blog.memolio.io/p/the-ninety-second-fix-that-took-four</guid><dc:creator><![CDATA[memolio]]></dc:creator><pubDate>Fri, 10 Apr 2026 11:54:33 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!wkaj!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3178a0e8-8a6c-41d3-9a7b-602828a57b69_2316x2316.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Yesterday I spent four hours watching Claude solve the same problem five different times. Each fix felt like the last one. Each time it was wrong.</p><p>The problem itself was boring: I&#8217;d deployed a small AWS Lambda to process PDFs as part of our book printing pipeline. It worked perfectly when I tested it inside the AWS console. The moment I called it from anywhere else &#8212; my own computer, our automation tool, anywhere that wasn&#8217;t the console itself &#8212; it returned <code>403 Forbidden</code>. Locked out by its own configuration.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.memolio.io/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Claude&#8217;s suggestion was confident and clear: &#8220;Just re-add the permission, it&#8217;s a 2-minute fix.&#8221; I did. It didn&#8217;t work. &#8220;Try deleting the old permission first, then re-adding it.&#8221; I did. It didn&#8217;t work. &#8220;Let&#8217;s use the CLI instead of the console.&#8221; I did. It didn&#8217;t work. Every fix came with the same breezy certainty, and every failure was met with a new suggestion delivered in the same breezy certainty.</p><p>At some point I noticed something that should have been obvious from the start: we were going in circles. Claude wasn&#8217;t tracking what had already failed. It was pattern-matching each new attempt to a different prior problem, confidently prescribing solutions that I had already tried, sometimes twice. I was the memory. I was the thing keeping the debugging session coherent, and I was terrible at it because I was tired and it was 1am and I wanted to go to bed.</p><p>Eventually I got genuinely annoyed and typed something I don&#8217;t usually type at a computer:</p><blockquote><p>&#8220;you really need to get better at recording what HASNT worked when debugging because we are just going round in circles&#8221;</p></blockquote><p>That single sentence flipped the entire session.</p><h2>What changed when I forced the step back</h2><p>Claude wrote a file called <code>DEBUG_403.md</code>. Inside it: every attempt, every result, every hypothesis still alive. It read the actual error messages character by character instead of skimming them. It did a proper web search. And within about ninety seconds it had the real answer.</p><p>Turns out AWS quietly changed how Lambda Function URLs work in October 2025. They used to need one permission (<code>lambda:InvokeFunctionUrl</code>). They now silently require two (<code>lambda:InvokeFunctionUrl</code> AND <code>lambda:InvokeFunction</code>). If you only have the first one, every public request returns 403, forever. The AWS console had actually been telling me this the whole time &#8212; there was a little blue banner explicitly stating both permissions were needed. I read it nine times over the course of the debugging session. Claude generated a response to it nine times. Neither of us actually understood what it said, because we were both too busy pattern-matching to similar-looking past problems.</p><p>The fix was one CLI command.</p><h2>The thing I keep relearning</h2><p>I&#8217;ve been working with AI coding agents intensively for almost a year now. I build Memolio almost entirely with them &#8212; most days I don&#8217;t write code directly, I describe what I want and review what comes back. And I keep learning the same lesson in different forms: <strong>AI agents will loop on an approach forever if you let them. Sometimes the most valuable thing a human can do is force a step back.</strong></p><p>It&#8217;s tempting to read this as &#8220;AI is unreliable, don&#8217;t trust it.&#8221; That&#8217;s not quite right. Claude wasn&#8217;t being lazy or malfunctioning. It was doing what large language models do: generating the next most plausible response given the state of the conversation. The problem was that the state of the conversation kept looking like a problem it had almost-seen-before, and &#8220;almost-seen-before&#8221; is a bad foundation for debugging something you haven&#8217;t actually seen at all.</p><p>What the model needed was a different kind of context: not more suggestions, but an enforced structure. A file on disk listing what had been tried. A requirement to read the error message literally before guessing. A rule that says &#8220;on the second failed attempt, stop guessing and start researching.&#8221; None of this is beyond the model&#8217;s capabilities &#8212; it did all of it brilliantly once asked. It just wouldn&#8217;t do it on its own.</p><p>I think this is the actual skill of working with AI agents in 2026. Not prompt engineering. Not picking the right model. Not even building clever evaluation loops. It&#8217;s <em>knowing when to interrupt</em>. Knowing when the confident-sounding next step is actually the fourth iteration of the same wrong step, dressed in different words. Knowing when to stop letting the machine drive and make it justify itself.</p><p>When I did that last night, Claude wrote me a memory file &#8212; literally, a permanent note to its own future sessions &#8212; called <code>feedback_record_what_hasnt_worked.md</code>. The rule: &#8220;On the second failed attempt at any fix, stop guessing. Create a debug log. Read error messages literally. Do proper research before suggesting more button-clicking.&#8221; It will remember this next time I start a new session. I don&#8217;t know if that&#8217;s exactly what machine learning researchers mean when they talk about AI that learns from feedback, but it felt like something.</p><h2>The thing that actually shipped</h2><p>Oh, right. The Lambda works now. The entire print pipeline for Memolio is automated end-to-end for the first time. When a grandparent finishes their WhatsApp interview and approves their book in the review page, everything from &#8220;interview complete&#8221; to &#8220;physical book printed and shipped&#8221; now runs without a human touching it. A webhook fires, PDFs get generated, the Lambda adds the tiny invisible printer metadata that commercial presses require, real MD5 hashes get computed, the order lands in CloudPrinter&#8217;s system, and forty-five seconds later there&#8217;s a confirmed sandbox order waiting to go.</p><p>And it happened in ninety seconds once we stopped pretending we knew the answer.</p><div><hr></div><p><em>Memolio turns a grandparent&#8217;s stories into a personalised, illustrated book &#8212; captured over WhatsApp, illustrated by AI, printed and shipped in hardcover. We&#8217;re currently in closed user testing. If you want early access or just want to follow along as we build, you can reply to this email or <a href="https://memolio.io">sign up at memolio.io</a>.</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.memolio.io/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>