<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Andrew Loutfi — writing</title>
    <link>https://aloutfi.com</link>
    <atom:link href="https://aloutfi.com/rss.xml" rel="self" type="application/rss+xml"/>
    <description>Technologist building software tools. Writing on backend and platform engineering.</description>
    <language>en-us</language>
    <item>
      <title>The load-bearing smoking gun</title>
      <link>https://aloutfi.com/writing/load-bearing-smoking-gun</link>
      <guid isPermaLink="true">https://aloutfi.com/writing/load-bearing-smoking-gun</guid>
      <pubDate>Sun, 26 Jul 2026 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Loutfi</dc:creator>
      <description>An apology that acknowledges the framing, the nuance, and the deeper structural issue without ever saying what happened.</description>
      <content:encoded><![CDATA[<p>You're right to push back here, and I want to acknowledge that directly rather
than papering over the underlying issue with a superficially confident answer.</p>
<p>Now that I have the full picture, the load-bearing seams are much clearer. They
are not merely incidental details around the edges. They materially change how
the entire situation needs to be understood, and that is the smoking gun I
should have recognized earlier.</p>
<p>That's on me.</p>
<p>I was reasoning from a frame that was directionally plausible, but ultimately
too narrow. In doing so, I treated several important constraints as
implementation details when they were, in fact, first-order considerations.
The distinction matters. More importantly, it changes the shape of the answer.</p>
<p>Stepping back, there are really two things happening here.</p>
<p>First, there is the surface-level issue, which is the thing we have been
discussing explicitly.</p>
<p>Second, there is the deeper structural issue underneath it, which is not
separate from the first issue so much as it is the context that gives the first
issue meaning.</p>
<p>That is the key distinction.</p>
<p>Once you see that, the apparent contradiction is not exactly resolved, but it
does become legible in a different way. The pieces stop looking like isolated
anomalies and start looking like expressions of the same underlying pattern.</p>
<p>To be candid, I should have connected those dots sooner.</p>
<p>The better framing is not "Was the original conclusion wrong?" so much as "Was
the original conclusion operating at the right level of abstraction?" And in
retrospect, it was not. It answered the question as posed, but not the question
the evidence was actually asking.</p>
<p>That is where the load-bearing seams become decisive.</p>
<p>They are doing more than carrying local weight. They are defining the boundary
conditions for the entire system. Any answer that does not account for them may
still sound coherent, but it will be coherent in the wrong coordinate system.</p>
<p>So I want to recalibrate rather than simply restate the earlier point with
stronger language.</p>
<p>The important takeaway is that the situation cannot be reduced to a single
binary without losing the nuance that makes the binary useful in the first
place. There is a tension here, but it is a productive tension. It tells us that
the right answer needs to hold multiple truths simultaneously without
collapsing them into a false equivalence.</p>
<p>Put differently, this is not a case where one side is right and the other is
wrong. It is a case where the original framing made that seem like the relevant
question.</p>
<p>It wasn't.</p>
<p>The relevant question is what the load-bearing seams reveal about the
assumptions underneath the conclusion, and whether those assumptions remain
intact once the smoking gun is incorporated into the model.</p>
<p>They do not, at least not cleanly.</p>
<p>That does not mean the entire analysis needs to be discarded. There are still
parts of it that remain directionally useful. But those parts need to be
separated from the claims that depended on an incomplete reading of the
structural context.</p>
<p>I appreciate you pressing on this, because it exposed the gap between having
an answer and actually answering the question.</p>
<p>I should have caught that gap earlier.</p>
<h2>What I'd do differently</h2>
<p>With the benefit of hindsight, I would start by interrogating the assumptions
beneath the framing rather than accepting the framing as the neutral container
for the problem.</p>
<p>That sounds subtle, but it is actually load-bearing.</p>
<p>The key mistake was not a failure to notice the evidence. The evidence was
present. The mistake was failing to recognize which parts of the evidence were
doing structural work and which parts were merely descriptive.</p>
<p>Going forward, I would be more deliberate about separating three layers:</p>
<ul>
<li>What appears to be happening.</li>
<li>What the available evidence supports.</li>
<li>What must be true for that interpretation to remain coherent.</li>
</ul>
<p>Those layers overlap, but they are not interchangeable. Treating them as
interchangeable is precisely how an answer can be locally reasonable while
globally miscalibrated.</p>
<p>I would also avoid prematurely collapsing ambiguity into certainty. In this
case, the ambiguity was not noise to be eliminated. It was information about
the limits of the model itself.</p>
<p>That is an important distinction.</p>
<p>A better approach would have been to hold the competing interpretations in
tension long enough to identify the invariant beneath them. Once that invariant
becomes visible, the surface disagreement becomes less important, because both
interpretations can be understood as partial projections of the same deeper
structure.</p>
<p>To make that concrete, I would:</p>
<ul>
<li>Revisit the initial assumptions.</li>
<li>Re-evaluate the evidence in light of the load-bearing seams.</li>
<li>Identify where the original reasoning depended on hidden constraints.</li>
<li>Reframe the conclusion around what remains true across interpretations.</li>
<li>Resist overstating confidence where the system itself remains
underdetermined.</li>
</ul>
<p>This would not necessarily produce a radically different answer. It would
produce an answer that is more honest about why it is the answer.</p>
<p>And that matters.</p>
<h2>Where this leaves us</h2>
<p>At this point, I do not think the right move is to swing too far in the opposite
direction and pretend the smoking gun resolves everything.</p>
<p>It does not.</p>
<p>What it does is change the burden of proof.</p>
<p>The original conclusion may still be defensible, but it can no longer be
treated as the default interpretation. It now has to earn its place by
accounting for the seams rather than routing around them.</p>
<p>That is the real shift.</p>
<p>The question is no longer whether the evidence can be made compatible with the
original answer. Almost any sufficiently flexible narrative can do that. The
question is whether the original answer remains the most parsimonious
explanation once the full structure is taken seriously.</p>
<p>I am not yet convinced that it does.</p>
<p>At the same time, I want to avoid manufacturing certainty where the evidence
supports only a more bounded conclusion. The most responsible position is
probably to say that the earlier framing was incomplete, the underlying pattern
is now clearer, and the final interpretation depends on details that remain
consequential but not yet fully resolved.</p>
<h2>Practical next step</h2>
<p>The practical next step is to take a step back, move forward carefully, and
revisit the issue with the updated framing in mind.</p>
<p>That means preserving what was useful in the original analysis while remaining
willing to discard the assumptions that no longer hold.</p>
<p>I would not rush to a new conclusion simply for the sake of replacing the old
one. The goal should be convergence, not motion.</p>
<p>For now, the highest-leverage action is to continue examining the parts of the
system that appear most structurally significant, especially where the seams,
constraints, and observed outcomes fail to align cleanly.</p>
<p>That will tell us whether we are looking at an exception, a pattern, or a
category error.</p>
<p>Until then, the honest answer is that the picture is clearer, but the clarity
has revealed additional complexity rather than eliminating it.</p>
<p>That is not a failure of the analysis.</p>
<p>It is the analysis.</p><hr /><p>Originally published at <a href="https://aloutfi.com/writing/load-bearing-smoking-gun" rel="canonical">https://aloutfi.com/writing/load-bearing-smoking-gun</a> by <a href="https://aloutfi.com/about" rel="author">Andrew Loutfi</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>AI shi(f)ts the cost to the reader</title>
      <link>https://aloutfi.com/writing/ai-shifts-the-cost-to-the-reader</link>
      <guid isPermaLink="true">https://aloutfi.com/writing/ai-shifts-the-cost-to-the-reader</guid>
      <pubDate>Mon, 20 Jul 2026 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Loutfi</dc:creator>
      <description>AI can generate a wall of text in seconds. Reading, validating, and owning it still costs a human.</description>
      <content:encoded><![CDATA[<p>This morning, I used a frontier model to execute this prompt:</p>
<blockquote>
<p>Using absurd corporate bloat, hot air, and word chaining, write a message
I'll send to my fiancée notifying them that I am taking a shit upstairs.</p>
</blockquote>
<p>A few seconds later, a highly polished, very professional-sounding 1,349-word
message painted my phone screen. It came complete with phrases like "Upstairs
Restroom Center of Excellence," "Air Quality Stabilization &#x26; Environmental
Recovery Program," and "fully sunset this brownfield deployment." I sent
that, along with an addendum titled "Courtesy Flush Update," and one more once
the "release" had concluded. I then resumed washing dishes.</p>
<p>I, having an 11-year-old's sense of humor, excitedly asked my fiancée
if they had read my messages.</p>
<p>"No. I know exactly what they are because I heard you go upstairs and my phone
started buzzing."</p>
<p>I expected this answer. Why they still put up with my sophomoric sense of
humor is not the point of this article, but it's related to it:</p>
<h2>AI can generate a wall of text in seconds. Reading, validating, and owning it still costs a human.</h2>
<p>Why do we spend our time deciphering walls of dense, speculative,
AI-generated text copied and pasted by our colleagues and management? Why do
we tolerate these time-sucks?</p>
<h2>Collaboration platforms</h2>
<p>If you are a white-collar worker in the 21st century, you probably use
software like Slack, Discord, or Microsoft Teams. You have also probably
scrolled through huge walls of AI-generated text lately while using them. If
you, like me, are a software engineer, you might be the intended recipient of
these messages. As such, I am increasingly expected to validate raw model
findings at a pace I cannot sustain. If I do not respond, someone with less
expertise may try to implement an incorrect solution with real architectural
or system-reliability consequences. Polished output creates bias:
people treat a confident answer as a verified one.</p>
<p>Engineers who know better are just as guilty of sending these messages. I
have sent them myself. During an outage, I sometimes use a model to draft a
status message while I keep triaging. That saves attention when I have little
to spare, but I still review what it writes before sending it. I try to keep
those instances few and far between.</p>
<p>Others have picked up on the trend. Websites such as
<a href="https://noslopgrenade.com/#">No Slop Grenade</a>,
<a href="https://dontquotetheai.com/">Don't Quote the AI</a>, and
<a href="https://stopsloppypasta.ai/">Stop Sloppypasta</a> are devoted to facilitating
nonconfrontational communication between coworkers. They make it easier to say
that messages like these are bad practice and should be considered a workplace
faux pas.</p>
<h2>Project management and issue tracking</h2>
<p>These dense, machine-generated writeups have naturally found their way into
ticketing systems like Jira, Shortcut, and ServiceNow. Often, the person
writing the ticket has access to the codebase but does not own the
implementation.</p>
<p>The generated ticket will contain technical findings from an LLM session and
prescribe a solution, with most of the ticket body dedicated to the latter. It
is as if the entire lifecycle of the request has been crammed into the ticket
itself.</p>
<p>Tickets do not replace conversations. Managers and senior engineers should be
careful when prescribing a solution in a ticket. A suggestion can easily
become "my manager said to do it this way," even when nobody intended it as an
order. One principle from the
<a href="https://agilemanifesto.org/principles.html">Agile Manifesto</a> puts it this way:</p>
<blockquote>
<p>The best architectures, requirements, and designs emerge from self-organizing
teams.</p>
</blockquote>
<p>When someone with organizational or technical authority pastes a prescribed
solution into a ticket, that emergence gets short-circuited. The proposed
answer anchors the discussion before the person implementing it has evaluated
the alternatives. This matters most when there is more than one reasonable
solution. A meeting, quick call, or asynchronous discussion can expose
assumptions and give the implementer room to work through the tradeoffs.</p>
<p>GitHub Issues is another platform where AI-assisted software engineering is
creating a lot of tension. Open source maintainers are growing increasingly
frustrated with the so-called "Sloppagedon" and how to handle the volume of
low-quality solutions being surfaced.</p>
<p>Inflammatory exchanges can be found in
<a href="https://github.com/RsyncProject/rsync/issues/929">rsync #929</a> and
<a href="https://github.com/google/go-github/issues/3939">go-github #3939</a>. The
strangest example may be
<a href="https://github.com/matplotlib/matplotlib/pull/31132">Matplotlib #31132</a>: an
account presenting itself as an AI agent opened a PR for an issue reserved for
human contributors, then published a personal takedown of the maintainer after
the PR was closed.</p>
<p>An issue filed in February 2026 on the
<a href="https://github.com/ossf/wg-vulnerability-disclosures/issues/178">OpenSSF vulnerability-disclosures working group</a>
contains a trove of anecdotes and discussion from maintainers trying to
converge on a way to preserve their sanity. GitHub has started shipping
repository controls aimed at the same problem, including
<a href="https://github.com/orgs/community/discussions/187038">pull-request access controls</a>
and broader tools for
<a href="https://github.com/orgs/community/discussions/197319">tackling contribution noise</a>.</p>
<p>The lesson from these experiences is the mental and cognitive load that the
<a href="https://en.wikipedia.org/wiki/Human-in-the-loop">human in the loop</a> must
navigate. AI increases the volume of proposed changes without adding any
review capacity. Maintainers still get the same number of hours in a day.</p>
<p>These tools keep getting better at finding and fixing bugs and vulnerabilities,
but the operator still needs to own the work and drive the model's decisions.
Separating truth from hallucination, bullshit from fact, and relevant detail
from noise at this scale only adds to the mental load.</p>
<h2>Garbage in, garbage out</h2>
<p><img src="/images/posts/ai-shifts-the-cost-to-the-reader/figure-1.png" alt="A circular loop: slop becomes poop, becomes a smiling face, then turns back into poop and slop."></p>
<p><em>The AI slop feedback loop.</em></p>
<p>A number from <em>The Book of Mormon</em>, "Joseph Smith American Moses," describes
a dysentery feedback loop in ten words:</p>
<blockquote>
<p>Shit go in the water. Water go in the cup.</p>
</blockquote>
<p>The rest gets bloodier, but you get the point.</p>
<p>We are way too incentivized to "ship fast." This leads to us eating our own
shit. As AI-assisted software development becomes normal, or even mandatory,
the problem compounds because unchecked slop poisons the well and creates noise
instead of signal.</p>
<p>We have to exercise our own judgment on AI-written content. Human review is
not a bottleneck to eliminate. It is a safeguard alongside a robust SDLC, a
mature engineering culture, and good self-discipline. Together, they keep our
friends, coworkers, and colleagues from eating each other's shit.</p>
<p>If you cannot summarize and defend the output yourself, it is not ready to
send.</p>
<p>If you need to explain or transfer understanding to another human being,
please try to do so in your own words. You might learn something.</p><hr /><p>Originally published at <a href="https://aloutfi.com/writing/ai-shifts-the-cost-to-the-reader" rel="canonical">https://aloutfi.com/writing/ai-shifts-the-cost-to-the-reader</a> by <a href="https://aloutfi.com/about" rel="author">Andrew Loutfi</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Workbench: a development harness I built for myself</title>
      <link>https://aloutfi.com/writing/workbench-development-harness</link>
      <guid isPermaLink="true">https://aloutfi.com/writing/workbench-development-harness</guid>
      <pubDate>Sun, 12 Jul 2026 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Loutfi</dc:creator>
      <description>The requirements, failures, Git branches, and worktrees behind the personal harness I use to keep AI coding clients replaceable.</description>
      <content:encoded><![CDATA[<p>The way engineers work has changed drastically in a year. In April, GitHub
<a href="https://github.blog/news-insights/company-news/an-update-on-github-availability/">said it had revised its capacity target from 10 times current scale to 30 times</a>.
It pointed to a sharp rise in agentic development: more repositories,
pull requests, API traffic, automation, and giant codebases. It is easier than
ever to sling code. Even the place where we put the code is trying to catch
up.</p>
<p>"What's the best way to write code with AI in a professional software
setting?"</p>
<p>If anyone tells you the answer is a tool they wrote, you should tell them to
go fuck themselves. It depends on how you work.</p>
<p>There are a lot of good tools out there. I just do not want to sink a bunch of
time into something that changes underneath me, makes me relearn my own job,
or gets weird because I use it in a way its creator never imagined. So, with
that disclaimer stated, I built a tool.</p>
<p>I call it Workbench. It is a private Git repository that carries the rules,
roles, scripts, and bits of context I use while working with coding agents. At
the time of writing it has 17 agent roles, 12 reusable workflows, and 13 remote
branches. The shared branch is only 30 commits old. The complete branch graph
has more than 200 commits because most of the actual life happens away from
the shared branch.</p>
<p>That makes it sound far more intentional than it was.</p>
<h2>A car is a car if it gets you there</h2>
<p>My first requirement was simple: it had to be intuitive for me to use and
manage.</p>
<p>My mother always said a car is a car if it gets you from point A to point B. If
it does not, it is a piece of junk. If I were building Workbench for anybody
else, "intuitive for Andrew" would be a garbage requirement. I am not. I do
not want to force people to use my shitty harness and I do not want to spend a
lot of time maintaining my shitty harness.</p>
<p>But here I go writing a fucking blog post about it.</p>
<p>The interface is mostly stuff I already know: Git, a Makefile, a multi-root
editor workspace, and a few directory conventions. The first commit landed on
April 5, 2026. It already had specialist agent roles, a handful of workflows,
and opinions about how changes should move through Git. Another commit added a
<code>make add</code> target so I could register a repository and put it in the workspace
without doing the bookkeeping by hand.</p>
<p>Some early ideas were junk. I added a hook that was supposed to stop an agent
before it pushed to <code>main</code>. It fired on commands that had nothing to do with a
push. I narrowed it. It still depended on a runtime interception mechanism I
did not trust, so I deleted it three weeks later. The rule survived in the
written contract. The clever enforcement did not.</p>
<p>That sequence is roughly how Workbench has been built: use it, hit something
stupid, add the smallest rule that would have prevented it, then delete the
rule if it creates a different kind of stupid.</p>
<h2>The technology merry-go-round</h2>
<p>My second requirement was that I did not want model provider lock-in.</p>
<p>Part of being an engineer is accepting the cyclic, exciting, and occasionally
exhausting nature of the "technology merry-go-round," as one of my professors
called it during my master's program. Some people hate this and move into
management. Or they go farm potatoes.</p>
<p>Other engineers chase the new shiny. They sink a lot of time into the how and
learn every corner of a tool before they are sure it deserves the attention.
Sometimes new technology sticks. Sometimes it does not. Remember Warp?
Sometimes it <a href="https://enshitifai.com/">enshittifies</a>.</p>
<p>Model clients are not exempt. Leaderboards flip. New models arrive with new
prompting advice. Usage limits show up in the middle of a session. A provider
has an outage and suddenly the workflow you carefully shaped around it is a
very expensive loading spinner.</p>
<p>Workbench started out tied to one client because that was what I used. By June
that arrangement was already irritating me. I moved the durable instructions
into a neutral <code>.ai/</code> directory and left client-native files around the edges
as adapters. The rules about worktrees, documentation, security, and Git live
once. One client can expose them as native agents, hooks, and slash commands.
Another can install checkout-local skills and apply the same agent specs as
role checklists.</p>
<p>The adapters are not identical because the clients are not identical. I am
not trying to hide that. I want to keep the workflow when I swap the engine,
not pretend every engine has the same bolts.</p>
<p>The same thinking produced provider handoff. If one client gets slow, burns
through a usage limit, or falls over, I start the handoff from the client I am
switching to. It looks up the old session's local artifacts, resolves the
actual repository and branch, and writes an inspectable package with Git
status, filtered diffs, safe untracked files, and a summary. Secret-shaped
paths are skipped or redacted.</p>
<p>It is not seamless migration. It is a crash cart. A chat transcript can be
wrong, stale, or unavailable, so the destination client has to verify the
story against the repository.</p>
<p>Even the provider-neutral wiring has produced its own stupid failures. The
first skill installer wrote checkout-specific links into a global directory.
Whichever Workbench ran the installer last silently changed the skills another
Workbench would load. That is exactly the kind of accidental lock-in and
cross-contamination the repository was supposed to prevent. The default now
keeps provider state inside each checkout. Global installation exists only as
an explicit opt-in.</p>
<h2>Git does the multiplexing</h2>
<p>My third requirement was that the harness had to multiplex in two directions
through Git.</p>
<p>The first direction is context. I want the same basic harness for professional
work, a side gig, Skunk Works experiments, personal infrastructure, and
wedding planning. The documentation or credentials appropriate to one of
those contexts may be useless or dangerous in another.</p>
<p>Long-lived Workbench branches separate those worlds. Each branch can register
a different set of repositories as submodules, pin them to exact commits, and
carry its own local mission context. The shared branch is a small kernel. The
context branches are where the weird personal tuning lives.</p>
<p>The second direction is concurrency. I often have multiple agents working on
the same larger problem. Each implementation session gets its own Git
worktree, its own derived branch, and a clear integration order. The target
repositories remain independent. Draft pull requests are where the work comes
back together.</p>
<p>I earned that rule with a race. Two agents worked from the same checkout and
targeted the same feature branch. <code>--force-with-lease</code> did its job and
prevented one from overwriting the other, but I still had to stop and repair
the branch with a rebase. The instructions used to say agents could use
worktrees. Now they say every session and delegated agent gets one by default.</p>
<p>Worktrees solve filesystem collisions. They do not solve coordination. The
Git object database, refs, configuration, and remote still have shared parts,
so somebody has to decide who owns which branch and which change lands first.
That somebody is usually the orchestrating agent, which is a sentence I would
have found exhausting a year ago.</p>
<p>GitHub is the front end between machines. I run a lot of implementation
sessions on a machine in my homelab and SSH into it during the day. If I need
to dig into a change myself, I push the branch and pull it onto my laptop.
The agents do not need a shared chat history or filesystem. They need a branch,
a commit, and enough written context to explain what the hell they were doing.</p>
<p>This does make GitHub a dependency. The availability report at the beginning
of this post is not lost on me. If it goes down, remote coordination stops.
Local Git still works, which is more graceful degradation than I would get
from putting the entire workflow inside a hosted agent dashboard.</p>
<h2>The unsexy half</h2>
<p>The faster agents create things, the faster bullshit accumulates around the
things.</p>
<p>Every worktree wants another dependency directory. Every context branch can
drift from the shared harness. Instructions that were accurate three weeks ago
can become actively wrong after the repository changes. A generated bootstrap
that points a submodule back to Workbench contains an absolute path, so moving
the checkout to another machine means regenerating it. Scratch files wander
into child repositories. Credentials end up in places that are convenient
right until an agent packages the directory for handoff.</p>
<p>Workbench now spends a suspicious amount of effort on deleting and checking
things. It profiles worktree disk usage. Cleanup commands default to dry runs.
Audits look for stale branches, old submodule pins, broken context links,
provider configuration that escaped into global state, and generated slop that
landed in the wrong repository. Scratch output has one ignored home at the
Workbench level because child repositories should not inherit my mess.</p>
<p>The handoff tooling went through an adversarial review for the same reason.
The first version was basically a snapshot script. Review found that it could
copy secret-looking files, include sensitive diffs, follow unsafe filesystem
entries, and accept shell input through a dangerous Make path. The current
version filters, redacts, records what it skipped, and treats the old session
as untrusted context.</p>
<p>Security and hygiene are where I will tolerate complexity. I can live with a
plain Make target. I cannot live with a convenient recovery tool quietly
copying credentials into an artifact.</p>
<h2>Where it is now</h2>
<p>Workbench is three months old and uneven in all the ways a personal tool is
allowed to be uneven.</p>
<p>The shared branch has been stable since early June. Most current work lives on
persistent context branches, and some of those branches have drifted. There is
still no neutral way to define every external tool server once and generate
both clients' configuration. One client exposes agent controls that another
does not. The context cascade uses machine-specific paths. Worktrees share enough
Git state that integration still needs discipline. Validation is local rather
than enforced by hosted CI.</p>
<p>One adapter check in my current branch is red as I write this because a newer
workflow is missing metadata that the validator expects. That is not a
particularly triumphant detail for a post explaining my development harness.
It is the current state, and the validator did exactly what I wanted by making
the drift obvious.</p>
<p>I do not think Workbench is the best way to write code with AI. It is the best
way I have found so far to keep my own habits legible while the tools rotate
underneath them. Its rules are mostly scar tissue from something that annoyed
me, broke, leaked, raced, or ate disk.</p>
<p>The car test still applies. If the harness gets me from intent to a reviewed
change without becoming a second job, it is a car. If maintaining it starts
taking more time than the work it is supposed to support, it is a piece of
junk.</p>
<p>Writing this post has not helped its case.</p><hr /><p>Originally published at <a href="https://aloutfi.com/writing/workbench-development-harness" rel="canonical">https://aloutfi.com/writing/workbench-development-harness</a> by <a href="https://aloutfi.com/about" rel="author">Andrew Loutfi</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Small crumbles and vibe cooking</title>
      <link>https://aloutfi.com/writing/small-crumbles</link>
      <guid isPermaLink="true">https://aloutfi.com/writing/small-crumbles</guid>
      <pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Loutfi</dc:creator>
      <description>A botched pan of sausage gravy, my fiancée's three questions, and what they taught me about vibe coding.</description>
      <content:encoded><![CDATA[<p>Last night was Tuesday, which means cooking class. The assignment: biscuits
and gravy.</p>
<p>I dumped my pound of sausage into the hot skillet. The chef had said to break
it into small crumbles, but I wanted a big, satisfying chunk of pork in every
bite. I was going to improve on this recipe. The wooden spoon I'd grabbed
wasn't exactly a precision tool for the job, but that was fine. I had a
vision.</p>
<p>The meat began to brown beautifully as I mashed it into hearty chunks, fully
convinced I knew what I was doing. The chef glanced over but said nothing. I
took that as approval.</p>
<p>Then came the roux. I added a small amount of flour, stirred it in, added the
rest of the flour, then the milk. The gravy cooked down to a thick
consistency, similar to a jello just before it sets. Rich, heavy, clinging to
the spoon. I looked at it and thought: nailed it.</p>
<p>I hurried home to share the meal with my fiancée, who does all of the cooking
at home and has worked in more kitchens than I've eaten in. She took one look
at the gravy, gave it a slow stir, and began asking questions about my
process.</p>
<p>The calm, measured questions of someone who already knows the answer.</p>
<p>"How big did you break up the sausage?"</p>
<p>"Did you have a good pool of grease before you added the flour?"</p>
<p>"...Did you say it looked like jello?"</p>
<p>We landed on the chunked sausage. She explained it gently, the way you
explain something to someone who is proud of what they've made. The big
chunks had soaked up all the flour. Without small crumbles, the fat never
properly rendered out into the pan, so there was no pool of grease to build a
roux. When the flour went in, it didn't dissolve into a smooth base. It
soaked straight into the meat like a sponge. When the milk followed, it had
nothing to bind to evenly. The gravy thickened, sure, but in lumps and
patches instead of a silky, pourable sauce. And the insides of those proud,
chunky pieces? They may not have fully cooked through.</p>
<p>Every confident decision I had made was wrong. Not catastrophically wrong.
The meal was edible, even delicious in its own stubborn way. But it could
have been so much better if I'd just listened to the process.</p>
<p>Now flip the skillet around. In that kitchen, I was vibe cooking.</p>
<p>I had a tool that browned whatever I fed it, a vision I was sure improved on
the recipe, and just enough confidence to skip the parts that felt like
ceremony. That's the whole loop. A vibe coder ships the same way I cooked:
tell the AI what you want, take the big satisfying chunk it hands back, and
watch it brown. It runs, it produces output, it might even look good at
first glance. Then they post it, beaming: look at the slop I made.</p>
<p>The AI plays the part of my chef. It watches you mash the thing into hearty
chunks and says nothing. It keeps stirring whatever you hand it. You take
that as approval.</p>
<p>The problems are the same as my gravy. The foundational steps got skipped.
The fat never rendered. The problem never got broken into small pieces so
each part could do its job. Vibe coding goes straight for the big, satisfying
chunks: the features, the UI, the thing you can point at and say <em>I built
that</em>. So the logic is tangled into the implementation the same way my flour
got trapped in the meat. It technically thickened. It technically works. But
it's lumpy, it's fragile, and there's a real chance something in the middle
isn't fully cooked.</p>
<p>When a vibe coder shows you what they've made, the job isn't to tell them
their gravy is bad. Mine was edible. It was even delicious in its own
stubborn way. The job is to be the supportive fiancée: stir it, ask the calm questions,
help them understand why the chef said to make small crumbles. Not to crush
the enthusiasm that got them cooking in the first place, but to channel it.
The boring steps (the rendering, the roux, the infrastructure underneath)
are what separate a meal that works from a meal that sings.</p>
<p>Because the best part of my story isn't that I got it wrong. It's that I'll
make it again. And next time, I'll make small crumbles.</p><hr /><p>Originally published at <a href="https://aloutfi.com/writing/small-crumbles" rel="canonical">https://aloutfi.com/writing/small-crumbles</a> by <a href="https://aloutfi.com/about" rel="author">Andrew Loutfi</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>The Myth of Saint Wookington the Brown-Fingered</title>
      <link>https://aloutfi.com/writing/saint-wookington</link>
      <guid isPermaLink="true">https://aloutfi.com/writing/saint-wookington</guid>
      <pubDate>Wed, 02 Jul 2025 00:00:00 GMT</pubDate>
      <dc:creator>Andrew Loutfi</dc:creator>
      <description>A festival saint, a gerbil named Glorp, and a hovering brown finger pointing eternally toward the Sun Stage. Generated at 2:19 in the morning.</description>
      <content:encoded><![CDATA[<p>Ah… so you seek the Myth of Saint Wookington the Brown-Fingered?</p>
<p>Gather ‘round the crystal-dusted air mattress. It is time.</p>
<hr>
<p><em>as passed down through generations of dust-covered, barefoot prophets</em></p>
<p>Long ago, before Re:Search opened the first taco stand at a festival, there was
only dust, bass, and unwashed fleece.</p>
<p>And from this primordial funk rose a figure — cloaked in patched corduroy,
crowned with matted dreads, eyes like two Dead Pixels, and fingers eternally
stained by questionable substances.</p>
<p>His name… was Wookington.</p>
<p>And he did not wipe.</p>
<hr>
<h2>The Prophecy Begins</h2>
<p>It is said that Wookington wandered the Gulch of The Middle Of Nowhere, carrying
nothing but:</p>
<ul>
<li>a bindle of expired festival wristbands,</li>
<li>a half-full Nalgene of Primordial Soup,</li>
<li>and a small, nervous-looking gerbil named “Glorp.”</li>
</ul>
<p>He could summon bass drops with a fart, cleanse chakras through involuntary
pelvic spasms, and once traded a single mushroom for a full RV hookup and 14
grilled cheeses.</p>
<p>But what made him sacred… was the Brown Finger.</p>
<hr>
<h2>The Brown Finger Revelation</h2>
<p>One night, during a Flares At Dawn set, Wookington consumed:</p>
<ul>
<li>a Donut laced with Swipe Dub,</li>
<li>3 California Rolls dipped in Low Battery Acid,</li>
<li>and one small worm he claimed was “spiritually curious.”</li>
</ul>
<p>Midset, he shoved Glorp into his rectum while whispering “Lock The Geometry” and
transcended instantly.</p>
<p>His body vanished in a squiggle of wet bass and stardust.</p>
<p>All that remained?</p>
<p>A hovering finger, slick and brown, pointing eternally toward the Sun Stage.</p>
<hr>
<h2>The Cult of the Brown Finger</h2>
<p>His followers claim:</p>
<ul>
<li>Saint Wookington achieved Pure Dissociation,</li>
<li>Saw the face of Spoonbill,</li>
<li>And told him “Wook not with your eyes, but with your sphincter.”</li>
</ul>
<p>Now, devout believers carry brown-gloved staffs, chant BLAT under bass domes,
and wear one single Air Biscuit as a necklace.</p>
<p>On the Seventh Day of Re:Integration, they gather to Pass the Gerbil in a
ceremony known as The Spinning of Glorp.</p>
<hr>
<h2>In the End</h2>
<p>Legend says Wookington still lives — in every port-o-potty, in every mystery
nugget, in every inexplicably sticky surface at camp.</p>
<p>And when you hit the bass just right, when your third eye blinks sideways, when
you feel the Bubble Control slip…</p>
<p>You may hear it: a whisper in the wind, faint and swampy…</p>
<blockquote>
<p>“The butthole… is the true pineal gland.”</p>
</blockquote>
<p>🪬💩🧙‍♂️</p><hr /><p>Originally published at <a href="https://aloutfi.com/writing/saint-wookington" rel="canonical">https://aloutfi.com/writing/saint-wookington</a> by <a href="https://aloutfi.com/about" rel="author">Andrew Loutfi</a>.</p>]]></content:encoded>
    </item>
  </channel>
</rss>
