<?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[Unruly Context]]></title><description><![CDATA[If you're building something from nothing, this is for you]]></description><link>https://letters.unrulycontext.com</link><image><url>https://substackcdn.com/image/fetch/$s_!OT9b!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a3f1bff-62dc-4705-88f5-934d21bcabd3_1024x1024.png</url><title>Unruly Context</title><link>https://letters.unrulycontext.com</link></image><generator>Substack</generator><lastBuildDate>Sat, 11 Apr 2026 04:00:28 GMT</lastBuildDate><atom:link href="https://letters.unrulycontext.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Adam Tervort]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[unrulycontext@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[unrulycontext@substack.com]]></itunes:email><itunes:name><![CDATA[adam]]></itunes:name></itunes:owner><itunes:author><![CDATA[adam]]></itunes:author><googleplay:owner><![CDATA[unrulycontext@substack.com]]></googleplay:owner><googleplay:email><![CDATA[unrulycontext@substack.com]]></googleplay:email><googleplay:author><![CDATA[adam]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Say It, Don't Spray It]]></title><description><![CDATA[In which I build an agentic writing companion, name it after something embarrassing, and end up on my couch on an iPad doing exactly what I hoped I would.]]></description><link>https://letters.unrulycontext.com/p/spray-agentic-writing-companion</link><guid isPermaLink="false">https://letters.unrulycontext.com/p/spray-agentic-writing-companion</guid><dc:creator><![CDATA[adam]]></dc:creator><pubDate>Thu, 19 Feb 2026 03:11:50 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/29eb0db7-1c98-4340-8793-75e8ced5c419_1376x768.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There&#8217;s a thing kids say when another kid is talking too fast and gets a little too enthusiastic about making their point. The words come out wet.</p><p><em>Say it, don&#8217;t spray it.</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.unrulycontext.com/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">I write about building with AI as a thinking partner. If you&#8217;re curious how, subscribe.</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>I dictate almost everything now. Ideas, plans, first drafts, feedback on drafts, replies to emails. I talk to computers the way people in the 80s imagined we&#8217;d talk to computers. And when I&#8217;m really going -- when the idea is right there and I need to get it out -- I spray it.</p><p>So the app is called Spray.</p><p>---</p><h2>What I Actually Wanted</h2><p>I love reading. I&#8217;m a reasonably strong writer. What I&#8217;m not great at is writing <em>for public consumption</em> -- the part where you take something that&#8217;s alive in your head and shape it into something that works on a page for someone who isn&#8217;t you.</p><p>That process takes me a long time. Longer than I&#8217;d like. And for a while I&#8217;ve been watching what&#8217;s happened in AI-assisted coding and thinking: <em>why doesn&#8217;t this exist for writing?</em></p><p>The experience I wanted was specific. Not &#8220;AI writes content for me.&#8221; Not a better text editor. I wanted something closer to what I get when I&#8217;m in a good coding session with Factory Droid -- a genuine back-and-forth where I can think out loud, get pushback, iterate on a draft together, and end up somewhere neither of us would have gotten alone.</p><p>I also knew from the start that dictation had to be central to how it worked. I talk way faster than I type. For getting ideas out and doing early iteration, I almost exclusively use voice now. The only times I reach for a keyboard anymore are when I physically can&#8217;t talk out loud, or when typing would genuinely be faster than the overhead of dictation setup. (The juice/squeeze calculation is real. Sometimes it&#8217;s just three words.)</p><p>So I had two things: a clear problem I wanted to solve, and a set of constraints that would shape the solution.</p><p>I started building.</p><p>---</p><h2>The Spec Phase (Where the Real Work Happened)</h2><p>I&#8217;ve written before about how the spec is the work. With coding, I&#8217;ve found that when I spend serious time planning before any code gets written, the code almost takes care of itself. The inverse is also true: if I rush to code, I end up with something that technically exists but doesn&#8217;t do what I actually wanted.</p><p>I believed this. And then I built the initial spec for Spray and immediately forgot I believed it.</p><p>The first version of my plan had 13 Python files in a nested structure. MagicLink authentication. A multi-user access model. A bunch of infrastructure I was excited about but didn&#8217;t actually need.</p><p>I ran a technical review through Factory Droid using the compound engineering workflow, and it had opinions. Good ones. The security review caught some real edge cases. But the more useful part was the scope review -- the questions that forced me to articulate who this was actually for and what it actually needed to do.</p><p><em>MagicLink login: who are the users?</em></p><p>Me. I&#8217;m the only user.</p><p><em>So you need a multi-user auth system because...?</em></p><p>I don&#8217;t. I need a token in an environment variable that keeps the app from being completely open to the internet. That&#8217;s it.</p><p>The 13-file architecture became four Python files. FastAPI on the back end, plain HTML on the front. No frontend framework. No login system. No unnecessary abstractions between me and the thing I was trying to build. Each cut made the project smaller, clearer, and more likely to actually get finished.</p><p><strong>Constraints aren&#8217;t limitations. They&#8217;re decisions made in advance.</strong> Every door you close before you start coding is a door you don&#8217;t have to reason about at 11pm when you&#8217;re tired and tempted to just add one more thing.</p><p>The final stack:</p><ul><li><p>Python FastAPI backend</p></li><li><p>HTML frontend (no framework)</p></li><li><p>Deepgram for dictation (fast API, supports custom dictionaries)</p></li><li><p>Claude API with a three-model setup: Sonnet 4.5 for daily work, Opus 4.5 when I need to go deep, Haiku when I need something quick</p></li><li><p>Railway for deployment, with a Railway volume as the persistent file system</p></li><li><p>GitHub as the deployment trigger -- commit, Railway builds the container, done</p></li></ul><p>No magic. Boring in the best way.</p><p>---</p><h2>The Agentic Part (This Is the Bit That&#8217;s Actually Different)</h2><p>Here&#8217;s where Spray is something different from a fancier writing tool.</p><p>The agent isn&#8217;t just responding to prompts. It has tools -- read files, write files, list files -- and it uses them autonomously as part of doing its job. When I give Spray a dictation and ask for a draft, the agent reads the relevant voice profile, reads corpus samples from my existing writing, checks if there are previous drafts of this piece, and <em>then</em> writes something. It&#8217;s not working from the context I happen to paste into the prompt. It&#8217;s building its own context before it acts.</p><p>This is what &#8220;agentic&#8221; actually means in practice, as opposed to the way the word gets thrown around. It&#8217;s not &#8220;AI that seems smart.&#8221; It&#8217;s an AI that takes sequences of actions -- with real tools, against real files -- in service of a goal you&#8217;ve given it. The difference in output quality is not subtle.</p><p>The file system was important to me for exactly this reason. I wanted the agent to have persistent memory across sessions in a form it could actually use. A Railway volume attached to the container gives it a real directory structure -- voice profiles, corpus samples, project folders, draft files -- that it can read from and write to on its own. Not a database the agent queries through an API. An actual file system the agent can navigate like a collaborator with filing access.</p><p>The context layer is where I spent the most time before I wrote a single line of application code. Voice and tone documents for each writing context. Corpus samples from my existing published work. Custom Deepgram dictionaries for each project -- because when I&#8217;m dictating something for BishopricOS, I use different vocabulary than when I&#8217;m dictating something for Unruly Context, and I don&#8217;t want the transcription guessing. Each custom dictionary took some upfront time and paid back immediately in transcription accuracy.</p><p>The agent also has skills -- structured instruction files that tell it how to handle specific tasks. How to triage a new dictation and recommend the right output format. How to draft for each of my different newsletters. How to generate derivative social posts once a main post is approved. The skills aren&#8217;t just system prompts; they&#8217;re persistent files the agent reads when it needs them, so they stay organized and editable without touching any code.</p><p>The result is something that feels -- and I want to be precise about this -- like working with a collaborator who has read everything I&#8217;ve written, knows what I&#8217;m trying to build, and remembers where we left off.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-jJf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8c5393-5404-4466-a1e0-2fb89376d1c5_1376x768.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-jJf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8c5393-5404-4466-a1e0-2fb89376d1c5_1376x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!-jJf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8c5393-5404-4466-a1e0-2fb89376d1c5_1376x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!-jJf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8c5393-5404-4466-a1e0-2fb89376d1c5_1376x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!-jJf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8c5393-5404-4466-a1e0-2fb89376d1c5_1376x768.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-jJf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8c5393-5404-4466-a1e0-2fb89376d1c5_1376x768.jpeg" width="1376" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1b8c5393-5404-4466-a1e0-2fb89376d1c5_1376x768.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1376,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:879009,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://letters.unrulycontext.com/i/188451792?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8c5393-5404-4466-a1e0-2fb89376d1c5_1376x768.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-jJf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8c5393-5404-4466-a1e0-2fb89376d1c5_1376x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!-jJf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8c5393-5404-4466-a1e0-2fb89376d1c5_1376x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!-jJf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8c5393-5404-4466-a1e0-2fb89376d1c5_1376x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!-jJf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b8c5393-5404-4466-a1e0-2fb89376d1c5_1376x768.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>---</p><h2>What It&#8217;s Like to Actually Use It</h2><p>I&#8217;m on my iPad right now. On the couch. This was the specific thing I wanted to be able to do, and it&#8217;s working.</p><p>The workflow for a new post is: I open Spray, I tap the dictation button, and I talk. The Deepgram integration is fast -- transcription happens in near-real-time, with the custom dictionary doing its job to get the vocabulary right. I review the transcription, occasionally fix a word or two, and submit it to the agent.</p><p>The agent triages it -- is this a full post? A short note? Which newsletter? -- and tells me what it thinks before it does anything. If I agree, it goes and does the work: reads the relevant files, drafts something, saves the draft to the project folder. I read the draft, dictate my feedback, and we iterate.</p><p>The model switching turned out to matter more than I expected. Sonnet is fast enough for most of the back-and-forth, but when I need the agent to really wrestle with something -- voice calibration on a tricky piece, structure for a complex idea -- Opus earns its cost. And for quick tasks where I just need the agent to check something or run a formatting pass, Haiku is fast enough to feel instant.</p><p>The derivative stack is one of my favorite things. Once I approve a main Substack post, I can ask Spray to generate all the social derivatives at once -- the Substack note, the LinkedIn post, the X post, the OG metadata and image prompt. What used to be a multi-session, copy-paste-and-reformat process is now a single conversation. The agent has the context of the main post, knows the platform rules for each derivative, and produces all of them without me re-explaining anything.</p><p>---</p><h2>The Thing That Surprised Me</h2><p>I went into this expecting the dictation piece to be the revelation. It&#8217;s good, and the Deepgram integration works better than I hoped. But the thing that actually surprised me was how different the agentic experience feels from prompting.</p><p>When I&#8217;m prompting a model -- copying in context, asking for something, copying out the output -- the AI is a tool I&#8217;m operating. When the agent has file access and real task structure, it&#8217;s a partner I&#8217;m directing. The distinction sounds semantic. It isn&#8217;t.</p><p>The agent tells me when a dictation doesn&#8217;t have enough depth for a full post and should be a Substack note instead. It asks clarifying questions before it drafts because it&#8217;s read the skill files that tell it to. It saves drafts with consistent naming conventions because that&#8217;s in the instructions. It does things I would have had to remember to ask for.</p><p>There&#8217;s a reason I&#8217;m more productive in a good coding session with an agent than I am with a static code assistant. The agent is doing work between my inputs, not just responding to each one. Writing agents can do the same thing, and now I have one.</p><p>---</p><h2>What&#8217;s Still Unfinished</h2><p>The app works. I&#8217;m using it daily. But there&#8217;s a list.</p><p>The mobile experience is fine, but it could be better. I built for &#8220;works on iPad&#8221; not &#8220;optimized for iPad,&#8221; and the difference shows up in the small things -- tap targets, the way the dictation button behaves when you&#8217;re holding the device sideways. I&#8217;ll get there.</p><p>I haven&#8217;t built the feedback loop yet. Right now, when a post performs well or a draft gets significantly revised before publishing, that learning doesn&#8217;t flow back into the corpus or the voice profile automatically. I have to do it manually. That&#8217;s fine for now; I&#8217;m one person writing for three newsletters. But the system is designed to support that loop, and I&#8217;ll build it eventually.</p><p>And there are almost certainly edge cases I haven&#8217;t hit yet. The technical review caught several before launch, but production always reveals things that testing doesn&#8217;t.</p><p>That&#8217;s not a problem. That&#8217;s just what it looks like when a thing is alive.</p><p>---</p><p>The name is embarrassing in the best way. Every time I open the app I think of a ten-year-old me getting teased for talking too fast and getting too excited.</p><p>Say it, don&#8217;t spray it.</p><p>Sure. But also: say it. Get it out. Don&#8217;t let the gap between the idea and the polished draft be the reason the thing never exists.</p><p>That&#8217;s what Spray is for.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.unrulycontext.com/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">I document zero-to-one builds -- how to move from idea to shipped. Free. No spam.</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><item><title><![CDATA[How I Stopped Re-Onboarding My AI Every Morning: Compound engineering with Factory Droid]]></title><description><![CDATA[A practical guide to compound engineering with Factory Droid. Build AI coding workflows that capture knowledge, prevent context loss, and improve every session.]]></description><link>https://letters.unrulycontext.com/p/compound-engineering-factory-droid</link><guid isPermaLink="false">https://letters.unrulycontext.com/p/compound-engineering-factory-droid</guid><dc:creator><![CDATA[adam]]></dc:creator><pubDate>Tue, 10 Feb 2026 17:04:20 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!3V3B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb876c25d-46c6-41de-92bb-f7c334d81084_2000x1125.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p><strong>TL;DR</strong>:</p><p>AI doesn&#8217;t forget because it&#8217;s dumb. It forgets because you didn&#8217;t build a system that remembers.</p><p>This post shows how I fixed that using compound engineering and Factory Droid.</p></blockquote><p>I&#8217;ve been coding with AI for about 14 months. Many active projects across Python, SvelteKit, Next.js, and FastAPI. I use Factory Droid as my daily driver &#8212; it&#8217;s where I live. And until today, every single one of those projects had the same problem.</p><p>I&#8217;d have a great coding session. Ship something real. Feel good about it. Close the terminal. And then when I came back &#8212; maybe the next day, maybe a week later &#8212; I&#8217;d spend the first few minutes trying to remember where I was. What was working. What was broken. What I&#8217;d been <em>deciding</em> right before I stopped.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.unrulycontext.com/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"><strong>Subscribe if you want fewer cold starts. </strong>I write about building durable systems for AI-assisted work &#8212; workflows, tools, and mental models that compound over time instead of resetting every session.</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>That&#8217;s bad enough. But here&#8217;s the part that everyone who codes with AI knows and dreads: <strong>your AI agent has the same problem, except worse.</strong></p><p>When you come back to a project after a week, you&#8217;ve at least got fuzzy memories. You remember the general shape of things. The agent remembers <em>nothing</em>. Every new session starts at absolute zero. It doesn&#8217;t know what you built yesterday, what patterns you established, what you tried and abandoned, or what decisions you were weighing. You spend the first several minutes &#8212; sometimes longer &#8212; just getting your AI partner oriented. Pasting in context. Explaining the codebase. Pointing it at the right files. And then halfway through a long session, when the context window compacts, it can forget again. You&#8217;re re-onboarding your own tool multiple times per session. 50 First Dates, but with a bot.</p><p>I&#8217;m a big believer in good documentation. I&#8217;m just not great at remembering to write it. And here&#8217;s the uncomfortable realization: in AI-assisted development, documentation isn&#8217;t just a nice-to-have for future-you. It&#8217;s the <em>operating system </em>for your AI partner. Without it, you&#8217;re hiring a brilliant contractor who shows up every morning with total amnesia.</p><p>That&#8217;s the knowledge decay loop, and it hits both sides of the partnership. Every productive session that ends without documentation is a loan against your future self <em>and</em> your future agent &#8212; with interest.</p><p>Today I read Every&#8217;s guide on compound engineering, and something clicked. This wasn&#8217;t just a system for organizing my own memory. It was a system for giving my AI partners the context they need to be useful from the first line of every session.</p><h2><strong>What Is Compound Engineering (And Why Should You Care)</strong></h2><p>The core idea is almost offensively simple: <strong>every unit of work should make subsequent work easier, not harder.</strong></p><p>Most codebases get harder to work with over time. Each feature adds complexity. After enough cycles, you&#8217;re spending more time fighting the system than building on it. Compound engineering inverts this. Bug fixes eliminate categories of future bugs. Patterns become tools. The codebase gets easier to understand, not harder.</p><p>The mechanism is a four-step loop: <strong>Plan &#8594; Work &#8594; Review &#8594; Compound.</strong></p><p>The first three steps are normal engineering. It&#8217;s the fourth that changes everything. After you ship, you capture what worked, what didn&#8217;t, and what the reusable insight is &#8212; then you feed it back into the system so the <em>next</em> cycle starts from a better position. Skip the compound step and you&#8217;ve done traditional engineering with AI assistance. Do it, and the system learns.</p><p>Every built a plugin for this &#8212; 26 specialized agents, 23 workflow commands, 13 skills &#8212; and shipped it for Claude Code. I don&#8217;t use Claude Code. I use Factory Droid.</p><p>So I made it work anyway. Here&#8217;s how.</p><h2><strong>Installing the Plugin (The Easy Part)</strong></h2><p><a href="https://docs.factory.ai/cli/configuration/plugins">Factory Droid&#8217;s docs</a> explicitly state Claude Code plugin compatibility. The install is two commands:</p><pre><code><code>droid plugin marketplace add https://github.com/EveryInc/compound-engineering-plugin
droid plugin install compound-engineering@compound-engineering-plugin
</code></code></pre><p>Note that second command &#8212; you need the <code>plugin@marketplace</code> format. If you just run <code>droid plugin install compound-engineering</code>, you&#8217;ll get an error about invalid plugin format. The marketplace name is <code>compound-engineering-plugin</code>(the repo name), so the full identifier is <code>compound-engineering@compound-engineering-plugin</code>.</p><p>You&#8217;ll see something like:</p><pre><code><code>Successfully installed compound-engineering@compound-engineering-plugin (e8f3bbc)
</code></code></pre><p>That hex string is the Git commit hash Droid pins to. You can verify the install by running <code>/plugins</code> inside a Droid session and checking the Installed tab &#8212; you should see the plugin with user scope, today&#8217;s date, and a cache path.</p><p>Great. Plugin installed. Now try running <code>/workflows:plan</code>.</p><p>Nothing happens.</p><h2><strong>The Gotcha (way to be non-standard, you Droid user you)</strong></h2><p>The plugin installs cleanly. It shows up in your installed plugins list. But the slash commands don&#8217;t register. Type <code>/plan</code> or <code>/workflows:plan</code> and Droid has no idea what you&#8217;re talking about.</p><p>This is a known issue &#8212; GitHub issue #31 on the compound engineering plugin repo. The root cause: the plugin&#8217;s command structure uses nested directories (<code>commands/workflows/plan.md</code>), and Droid doesn&#8217;t auto-register commands from plugin subdirectories the way Claude Code does. The plugin format is <em>compatible</em>, but the command discovery isn&#8217;t.</p><p>The fix is manual, and it takes about two minutes.</p><p>First, find where Droid cached the plugin:</p><pre><code><code>ls ~/.factory/plugins/cache/compound-engineering-plugin/compound-engineering/
</code></code></pre><p>You&#8217;ll see a directory named with the commit hash from your install. Inside it:</p><pre><code><code>CHANGELOG.md  commands/  droids/  LICENSE  README.md  skills/
</code></code></pre><p>Good news: the plugin already uses <code>droids/</code> instead of <code>agents/</code>, so the naming matches Factory Droid&#8217;s conventions. Now copy everything to your user-level Droid config:</p><pre><code><code>mkdir -p ~/.factory/commands ~/.factory/droids ~/.factory/skills

cp -r ~/.factory/plugins/cache/compound-engineering-plugin/compound-engineering/[hash]/commands/* ~/.factory/commands/
cp -r ~/.factory/plugins/cache/compound-engineering-plugin/compound-engineering/[hash]/droids/* ~/.factory/droids/
cp -r ~/.factory/plugins/cache/compound-engineering-plugin/compound-engineering/[hash]/skills/* ~/.factory/skills/
</code></code></pre><p>Replace <code>[hash]</code> with the actual commit hash directory name.</p><p>Restart Droid. Type <code>/plan</code>. It autocompletes. You now have <code>/plan</code>, <code>/work</code>, <code>/brainstorm</code>, <code>/deepen-plan</code>, <code>/technical_review</code>, <code>/document-review</code>, and everything else &#8212; registered as top-level commands. The <code>workflows:</code>namespace prefix gets dropped, which is actually cleaner for daily use.</p><p>That&#8217;s the entire technical setup. Everything from here is about making it actually useful.</p><h2><strong>The Foundation: Your Engineering Constitution</strong></h2><p>A plugin gives you commands. But commands without context produce generic results. The thing that makes compound engineering compound is the <em>context</em> &#8212; the accumulated knowledge about how you work, what you care about, and what your projects look like.</p><p>That context lives in two places.</p><h3><strong>Global AGENTS.md</strong></h3><p>Factory Droid reads <code>~/.factory/AGENTS.md</code> at the start of every session across all your projects. Think of this as your engineering constitution &#8212; the baseline expectations that apply everywhere, regardless of which project you&#8217;re in.</p><p>Mine includes:</p><p><strong>A Session Protocol.</strong> The agent reads <code>docs/STATUS.md</code> at the start of every session and updates it at the end. If I forget, it reminds me. This single habit solves about 80% of the &#8220;where was I?&#8221; problem.</p><p><strong>Test-Driven Development as a core methodology.</strong> Write tests first, always. The agent is instructed to pause me if I jump into implementation without tests. More on this later &#8212; there&#8217;s a story here.</p><p><strong>A security baseline.</strong> Input validation, parameterized queries, secrets in env vars, auth on every endpoint. I listed security as a growth area in my AGENTS.md because it is, and I&#8217;d rather the agent be proactive about it than wait for me to ask.</p><p><strong>The compound engineering loop itself, with TDD included.</strong> Plan &#8594; TDD &#8594; Work &#8594; Review &#8594; Compound, with specific instructions for each step. The agent knows the sequence and knows not to skip the compound step.</p><p><strong>Communication preferences.</strong> Speak at a systems level. Explain your reasoning. If there&#8217;s a better architectural approach, propose it &#8212; don&#8217;t just implement what I asked for.</p><p>The global AGENTS.md provides defaults. Each project has its own AGENTS.md in the project root that adds project-specific patterns, stack details, and lessons learned. Project-level takes precedence when they conflict.</p><h3><strong>STATUS.md (The Session Continuity System)</strong></h3><p>Every project gets a <code>docs/STATUS.md</code> that answers five questions: What&#8217;s the project? What&#8217;s done? What&#8217;s in progress? What&#8217;s next? What decisions are pending?</p><p>That last one &#8212; <strong>Open Decisions</strong> &#8212; is the most valuable section. &#8220;What was I building&#8221; is recoverable. You can look at the code, read the commit history, figure it out. But &#8220;what was I <em>deciding</em> and which way was I leaning&#8221; &#8212; that vanishes completely between sessions. If you&#8217;re weighing two approaches to auth and you close the terminal without documenting your reasoning, future-you either reverse engineers or repeats the process. Let&#8217;s not do that, shall we?</p><p>I built a slash command called <code>/init-project-docs</code> that bootstraps the entire docs structure for any project. Run it once, and the agent creates <code>docs/STATUS.md</code> (auto-populated from your README and package.json), plus empty directories for <code>plans/</code>, <code>solutions/</code>, <code>decisions/</code>, and <code>brainstorms/</code>. Under 30 seconds, and you never have to remember the template structure.</p><h2><strong>The First Real Test: BishopricOS</strong></h2><p>Theory is great. Does it actually work?</p><p>I took this system into BishopricOS &#8212; a Notion-based operating system for church leadership that I&#8217;m rebuilding as a standalone web app. I needed to add a wiki feature: sections, pages, version history, public sharing, the works.</p><h3><strong>Brainstorm &#8594; Plan &#8594; Deepen-Plan: The Best Planning I&#8217;ve Ever Done</strong></h3><p>I started with <code>/brainstorm</code> because the requirements were fuzzy. I knew I wanted a wiki. I didn&#8217;t know exactly what that meant for this app, this user base, this tech stack. When you&#8217;re building for volunteer church leaders who rotate every few years, &#8220;wiki&#8221; doesn&#8217;t mean the same thing as it does for a developer team.</p><p>As always, I started by dictating as much context as I could. I use VoiceInk for this (though MacWhisper is also excellent). I&#8217;ve had amazing results when working with AI coding partners when I dictate much more than I type, especially during brainstorming and planning. (And let&#8217;s be real--it makes me feel like I&#8217;m on Star Trek to just talk to the computer.)</p><p>The brainstorm command asked me targeted questions after I gave it my dictation dump &#8212; one at a time, not a wall of twenty &#8212; about purpose, users, constraints, and edge cases. Who creates content? Who reads it? Does content need to be public or just internal? By the end, I had clarity I wouldn&#8217;t have reached by just thinking about it, because the questions forced me to confront decisions I was unconsciously deferring.</p><p>Then <code>/plan</code>. The agent researched the existing codebase &#8212; not just the file structure, but the patterns I&#8217;d already established. It found my Prisma schema conventions, my API route structure, my auth patterns with Clerk. And it produced a structured implementation plan that actually matched how the rest of the app was built. This is the part that surprised me most. It wasn&#8217;t generic &#8220;here&#8217;s how to build a wiki&#8221; advice &#8212; it was &#8220;here&#8217;s how to build a wiki that fits <em>this specific codebase</em>.&#8221;</p><p>I pushed back on scope. &#8220;This is too much for one session &#8212; break it into phases.&#8221; It restructured into six phases: database models and CRUD API first, then Tiptap editor integration, drag-and-drop ordering, public page routes, version history UI, and search. Each phase buildable and shippable independently. That kind of progressive disclosure is hard to do well, and I would have been tempted to build it all at once and end up with something half-finished.</p><p>Then <code>/deepen-plan</code>. This is where it got genuinely impressive. The command spawns 40+ parallel research agents that go deep on the plan &#8212; checking framework docs for SvelteKit-specific patterns, looking for best practices around wiki-style content management, analyzing edge cases I hadn&#8217;t considered. Things like: what happens to public share links when a page is deleted? How should version history interact with the wiki section hierarchy? Should page slugs be auto-generated or user-defined?</p><p>The plan that came back was <em>significantly</em> better than what I would have written myself. Not because I couldn&#8217;t have gotten there eventually, but because I would have skipped half the research and gone straight to building. I would have discovered those edge cases in production, filed mental notes to fix them later, and either never gotten back to them or interrupted the flow of the work by trying to fix things right away rather than sticking to the plan. (That&#8217;s my kryponite. Always finding &#8216;little things&#8217; that will only take a moment to fix. Sure! That&#8217;s exactly how it always works. Promise.) The plan caught them before a single line of code was written.</p><p><strong>This was the single highest-value part of the entire system.</strong> The 80/20 rule from compound engineering is real &#8212; 80% of the value is in planning and review, 20% is in execution. When the plan is right, the code practically writes itself. When the plan is wrong, all the AI-assisted coding speed in the world just gets you to the wrong place faster.</p><h3><strong>Technical Review: Parallel Skepticism</strong></h3><p>After implementation, <code>/technical_review</code> spawns a dozen specialized agents that review the code simultaneously &#8212; security, performance, architecture, data integrity, code simplicity. Each returns prioritized findings: P1 (must fix), P2 (should fix), P3 (nice to fix).</p><p>I&#8217;ll be honest: I expected this to be the least useful step. I&#8217;d already reviewed the code during implementation. The tests passed. What else was there?</p><p>A lot, as it turns out. It caught real issues at every stage. Auth boundaries that weren&#8217;t tight enough on the wiki page deletion endpoint &#8212; a user could potentially delete pages in sections they didn&#8217;t own by manipulating the API directly. A database query pattern that wasn&#8217;t properly scoped to the current tenant, which in a multi-tenant app is the kind of bug that causes you to want to become a tech-free monk. Performance concerns about how version history was being loaded (fetching all versions when only the latest was needed for the default view).</p><p>None of these were things I would have caught in my own review. Not because I&#8217;m careless, but because I was thinking about whether the feature <em>worked</em>. The review agents were thinking about whether it was <em>safe</em>, <em>fast</em>, and <em>correct at the edges</em>. Different questions, and both matter.</p><p>The graphic I made for this post labels the space between <code>/work</code> and <code>/technical_review</code> as the &#8220;Knowledge Decay Zone&#8221; &#8212; that&#8217;s the gap where you&#8217;ve built something and it feels done, but you haven&#8217;t stress-tested it yet. Lots of bugs that ship to prod in that gap.</p><p>The compound engineering guide suggests asking three questions before accepting any AI output:</p><ol><li><p>&#8220;What was the hardest decision you made here?&#8221;</p></li><li><p>&#8220;What alternatives did you reject, and why?&#8221;</p></li><li><p>&#8220;What are you least confident about?&#8221;</p></li></ol><p>These are incredibly effective. The agent knows where its weak points are. It knows which parts of the implementation were judgment calls. But it won&#8217;t volunteer that information unless you ask. These three questions are the magic pixie dust for getting honest answers from your AI coding partner.</p><h3><strong>The TDD Gap</strong></h3><p>Here&#8217;s where it gets interesting. After Phase 1 of the wiki feature shipped, the summary reported &#8220;All 366 existing tests pass.&#8221; That sounds great. But 366 was the number I <em>started</em> with. No new tests were written for the new feature. The agent built the wiki, verified nothing else broke, and called it done.</p><p>The compound engineering loop has Plan, Work, Review, and Compound. It doesn&#8217;t have a dedicated TDD step. And my global AGENTS.md says &#8220;write tests first&#8221; &#8212; but the slash commands don&#8217;t enforce it. The system had a gap.</p><p>So I built <code>/tdd</code>.</p><p>It&#8217;s a custom slash command that bridges <code>/plan</code> and <code>/work</code>. After you approve a plan, <code>/tdd</code> reads it, identifies every testable behavior &#8212; API responses, auth boundaries, database operations, edge cases &#8212; presents a test plan for your approval, then writes tests that all <strong>fail</strong>. Every single one. That failing state is your starting line. Then when you run <code>/work</code>, the agent implements until those tests go green.</p><p>The key safeguard: if any new test <em>passes</em> before implementation, it flags it &#8212; because that means the test is either redundant or not testing what it claims.</p><p>The updated loop: <br><code>/plan &#8594; /tdd &#8594; /work &#8594; /technical_review &#8594; /compound</code></p><p>This was compound engineering compounding on itself. I used the system, found a gap, built a fix, and now every future session benefits. That&#8217;s the whole point.</p><h2><strong>The Cheat Sheet</strong></h2><p>This is what I keep open during coding sessions now. The full daily reference.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3V3B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb876c25d-46c6-41de-92bb-f7c334d81084_2000x1125.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3V3B!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb876c25d-46c6-41de-92bb-f7c334d81084_2000x1125.png 424w, https://substackcdn.com/image/fetch/$s_!3V3B!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb876c25d-46c6-41de-92bb-f7c334d81084_2000x1125.png 848w, https://substackcdn.com/image/fetch/$s_!3V3B!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb876c25d-46c6-41de-92bb-f7c334d81084_2000x1125.png 1272w, https://substackcdn.com/image/fetch/$s_!3V3B!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb876c25d-46c6-41de-92bb-f7c334d81084_2000x1125.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3V3B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb876c25d-46c6-41de-92bb-f7c334d81084_2000x1125.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b876c25d-46c6-41de-92bb-f7c334d81084_2000x1125.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2801588,&quot;alt&quot;:&quot;A meticulously labeled blueprint diagram showing a five-step AI development loop that exists entirely to remind you to write things down so Future You doesn&#8217;t hate Present You.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://letters.unrulycontext.com/i/187530615?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb876c25d-46c6-41de-92bb-f7c334d81084_2000x1125.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A meticulously labeled blueprint diagram showing a five-step AI development loop that exists entirely to remind you to write things down so Future You doesn&#8217;t hate Present You." title="A meticulously labeled blueprint diagram showing a five-step AI development loop that exists entirely to remind you to write things down so Future You doesn&#8217;t hate Present You." srcset="https://substackcdn.com/image/fetch/$s_!3V3B!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb876c25d-46c6-41de-92bb-f7c334d81084_2000x1125.png 424w, https://substackcdn.com/image/fetch/$s_!3V3B!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb876c25d-46c6-41de-92bb-f7c334d81084_2000x1125.png 848w, https://substackcdn.com/image/fetch/$s_!3V3B!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb876c25d-46c6-41de-92bb-f7c334d81084_2000x1125.png 1272w, https://substackcdn.com/image/fetch/$s_!3V3B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb876c25d-46c6-41de-92bb-f7c334d81084_2000x1125.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h3><strong>The Loop (Every Feature)</strong></h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lZV4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32a6fd4f-d758-4d7d-96cc-d7deec24fb0d_1192x586.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lZV4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32a6fd4f-d758-4d7d-96cc-d7deec24fb0d_1192x586.png 424w, https://substackcdn.com/image/fetch/$s_!lZV4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32a6fd4f-d758-4d7d-96cc-d7deec24fb0d_1192x586.png 848w, https://substackcdn.com/image/fetch/$s_!lZV4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32a6fd4f-d758-4d7d-96cc-d7deec24fb0d_1192x586.png 1272w, https://substackcdn.com/image/fetch/$s_!lZV4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32a6fd4f-d758-4d7d-96cc-d7deec24fb0d_1192x586.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lZV4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32a6fd4f-d758-4d7d-96cc-d7deec24fb0d_1192x586.png" width="1192" height="586" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/32a6fd4f-d758-4d7d-96cc-d7deec24fb0d_1192x586.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:586,&quot;width&quot;:1192,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:103654,&quot;alt&quot;:&quot;Screenshot of a simple reference table listing the five steps of the compound engineering loop, converted into an image because the publishing platform does not support inline tables.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://letters.unrulycontext.com/i/187530615?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32a6fd4f-d758-4d7d-96cc-d7deec24fb0d_1192x586.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Screenshot of a simple reference table listing the five steps of the compound engineering loop, converted into an image because the publishing platform does not support inline tables." title="Screenshot of a simple reference table listing the five steps of the compound engineering loop, converted into an image because the publishing platform does not support inline tables." srcset="https://substackcdn.com/image/fetch/$s_!lZV4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32a6fd4f-d758-4d7d-96cc-d7deec24fb0d_1192x586.png 424w, https://substackcdn.com/image/fetch/$s_!lZV4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32a6fd4f-d758-4d7d-96cc-d7deec24fb0d_1192x586.png 848w, https://substackcdn.com/image/fetch/$s_!lZV4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32a6fd4f-d758-4d7d-96cc-d7deec24fb0d_1192x586.png 1272w, https://substackcdn.com/image/fetch/$s_!lZV4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F32a6fd4f-d758-4d7d-96cc-d7deec24fb0d_1192x586.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Yes, this is a screenshot of a table. </strong>Substack still doesn&#8217;t support inline tables, and I needed this to render correctly in the year of our Lord 2026.</figcaption></figure></div><p><strong>Step 1: /plan [feature]<br></strong>Research codebase + create implementation plan</p><p><strong>Step 2: /tdd<br></strong>Generate failing tests from the plan</p><p><strong>Step 3: /work<br></strong>Agent implements until tests go green</p><p><strong>Step 4: /technical_review<br></strong>Multi-agent code review (security, perf, architecture)</p><p><strong>Step 5: /compound<br></strong>Capture what was learned, don&#8217;t skip this</p><h3><strong>Session Discipline</strong></h3><p><strong>Start:</strong> Agent reads <code>docs/STATUS.md</code>, orients you in 30 seconds.</p><p><strong>End:</strong> Agent updates <code>docs/STATUS.md</code>. Run test suite. Run <code>/compound</code> if you solved something non-trivial.</p><h3><strong>Other Commands Worth Knowing</strong></h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TpqL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe81ae0e5-1fc2-4e81-950e-5c160485f379_1198x832.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TpqL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe81ae0e5-1fc2-4e81-950e-5c160485f379_1198x832.png 424w, https://substackcdn.com/image/fetch/$s_!TpqL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe81ae0e5-1fc2-4e81-950e-5c160485f379_1198x832.png 848w, https://substackcdn.com/image/fetch/$s_!TpqL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe81ae0e5-1fc2-4e81-950e-5c160485f379_1198x832.png 1272w, https://substackcdn.com/image/fetch/$s_!TpqL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe81ae0e5-1fc2-4e81-950e-5c160485f379_1198x832.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TpqL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe81ae0e5-1fc2-4e81-950e-5c160485f379_1198x832.png" width="1198" height="832" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e81ae0e5-1fc2-4e81-950e-5c160485f379_1198x832.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:832,&quot;width&quot;:1198,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:146968,&quot;alt&quot;:&quot;Screenshot of a reference table listing additional Factory Droid slash commands and when to use them, displayed as an image for compatibility with the publishing platform.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://letters.unrulycontext.com/i/187530615?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe81ae0e5-1fc2-4e81-950e-5c160485f379_1198x832.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Screenshot of a reference table listing additional Factory Droid slash commands and when to use them, displayed as an image for compatibility with the publishing platform." title="Screenshot of a reference table listing additional Factory Droid slash commands and when to use them, displayed as an image for compatibility with the publishing platform." srcset="https://substackcdn.com/image/fetch/$s_!TpqL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe81ae0e5-1fc2-4e81-950e-5c160485f379_1198x832.png 424w, https://substackcdn.com/image/fetch/$s_!TpqL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe81ae0e5-1fc2-4e81-950e-5c160485f379_1198x832.png 848w, https://substackcdn.com/image/fetch/$s_!TpqL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe81ae0e5-1fc2-4e81-950e-5c160485f379_1198x832.png 1272w, https://substackcdn.com/image/fetch/$s_!TpqL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe81ae0e5-1fc2-4e81-950e-5c160485f379_1198x832.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>A perfectly reasonable table, doing its best in a hostile environment.</em></figcaption></figure></div><p><strong>/brainstorm <br></strong>Use this when requirements are fuzzy and you need to explore before committing to a plan.</p><p><strong>/deepen-plan<br></strong>When the plan exists, but needs real depth. Spins up parallel research agents to fill in the gaps.</p><p><strong>/document-review<br></strong>Review brainstorms or plans for clarity, gaps, and contradictions before execution.</p><p><strong>/triage<br></strong>Walk through review findings one by one instead of trying to hold everything in your head at once.</p><p><strong>/changelog<br></strong>Generate a changelog from recent merges without reconstructing history manually.</p><p><strong>/lfg [feature]<br></strong>Full autopilot: plan &#8594; build &#8594; review &#8594; PR.<br>For when you&#8217;re feeling bold and the safety nets are in place.</p><h3><strong>Key File Locations</strong></h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Da4U!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0482213-d34f-40cc-9f7a-e47ae3d1554a_1016x708.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Da4U!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0482213-d34f-40cc-9f7a-e47ae3d1554a_1016x708.png 424w, https://substackcdn.com/image/fetch/$s_!Da4U!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0482213-d34f-40cc-9f7a-e47ae3d1554a_1016x708.png 848w, https://substackcdn.com/image/fetch/$s_!Da4U!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0482213-d34f-40cc-9f7a-e47ae3d1554a_1016x708.png 1272w, https://substackcdn.com/image/fetch/$s_!Da4U!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0482213-d34f-40cc-9f7a-e47ae3d1554a_1016x708.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Da4U!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0482213-d34f-40cc-9f7a-e47ae3d1554a_1016x708.png" width="1016" height="708" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d0482213-d34f-40cc-9f7a-e47ae3d1554a_1016x708.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:708,&quot;width&quot;:1016,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:119186,&quot;alt&quot;:&quot;Screenshot of a reference table listing important Factory Droid configuration files and directories, presented as an image due to lack of table support.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://letters.unrulycontext.com/i/187530615?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0482213-d34f-40cc-9f7a-e47ae3d1554a_1016x708.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Screenshot of a reference table listing important Factory Droid configuration files and directories, presented as an image due to lack of table support." title="Screenshot of a reference table listing important Factory Droid configuration files and directories, presented as an image due to lack of table support." srcset="https://substackcdn.com/image/fetch/$s_!Da4U!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0482213-d34f-40cc-9f7a-e47ae3d1554a_1016x708.png 424w, https://substackcdn.com/image/fetch/$s_!Da4U!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0482213-d34f-40cc-9f7a-e47ae3d1554a_1016x708.png 848w, https://substackcdn.com/image/fetch/$s_!Da4U!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0482213-d34f-40cc-9f7a-e47ae3d1554a_1016x708.png 1272w, https://substackcdn.com/image/fetch/$s_!Da4U!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0482213-d34f-40cc-9f7a-e47ae3d1554a_1016x708.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Another table, now safely embalmed as an image. </strong>At this point it&#8217;s a design system.</figcaption></figure></div><p><strong>~/.factory/AGENTS.md<br></strong>Global agent configuration. Applies to all projects unless explicitly overridden.</p><p><strong>~/.factory/commands/<br></strong>Your custom slash commands. This is where workflow discipline actually lives.</p><p><strong>~/.factory/droids/<br></strong>Specialized sub-agents with narrow responsibilities and opinions.</p><p><strong>~/.factory/skills/<br></strong>Domain expertise the agents can reuse instead of relearning every project.</p><p><strong>./AGENTS.md<br></strong>Project-level configuration. Overrides global defaults when they conflict.</p><p><strong>./docs/STATUS.md<br></strong>Current project state.<br>Read this first. Update it last. Future You is counting on it.</p><p><strong>./docs/plans/<br></strong>Implementation plans generated by /plan and refined by /deepen-plan.</p><p><strong>./docs/solutions/<br></strong>Solved problems. This is the compound interest account.</p><h2><strong>What This Actually Cost</strong></h2><p>Total setup time: about 45 minutes from zero to a working system. That includes the plugin install, troubleshooting the command registration issue, creating the global AGENTS.md, building the STATUS.md template and <code>/init-project-docs</code>command, and building the custom <code>/tdd</code> command.</p><p>45 minutes of setup. The first coding session after that was the best I&#8217;ve ever had. Not the most productive in terms of lines of code (which is a dumb way to measure productivity, at least in my opinion) &#8212; the planning took longer than I&#8217;m used to. But the <em>output</em> was better than anything I&#8217;ve shipped from a single session. Tested, reviewed, documented, and with a clear path to the next phase. No knowledge debt. No &#8220;I&#8217;ll document this later.&#8221; No future-me cursing past-me for leaving him with nothing.</p><h2><strong>The Point</strong></h2><p>Here&#8217;s the mental model that ties it all together.</p><p>Compound engineering treats AI-assisted coding as a <em>knowledge</em> multiplier, not a speed multiplier. Each session doesn&#8217;t just produce code &#8212; it produces plans, tests, review findings, and documented solutions that make the next session start from a higher baseline. The code is a side effect. The system is the product.</p><p>The difference between &#8220;I built a wiki feature today&#8221; and &#8220;I built a wiki feature today <em>and</em> my project now has better documentation, a tested API surface, reviewed security boundaries, and a searchable record of how I solved the tricky parts&#8221; &#8212; that difference compounds. Three months from now, the second version of you is operating in a fundamentally different universe than the first.</p><p>Each cycle makes the next one easier. That&#8217;s the whole game.</p><div><hr></div><p><em>The compound engineering plugin is built by Every. The guide is at <a href="https://every.to/guides/compound-engineering">every.to/guides/compound-engineering</a>. The plugin repo is at <a href="https://github.com/EveryInc/compound-engineering-plugin">github.com/EveryInc/compound-engineering-plugin</a>. Factory Droid&#8217;s plugin docs are at <a href="https://docs.factory.ai/cli/configuration/plugins">docs.factory.ai/cli/configuration/plugins</a>.</em></p><p><em>This post was co-written with Claude. The code was co-written with Factory Droid, using Opus 4.5. (&#8217;cmon Factory team, I want to use the shiny new Opus 4.6 already!) The graphic was designed with Nano Banana Pro. The system that made it all work was Every&#8217;s compound engineering. Turtles all the way down.</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.unrulycontext.com/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">No hype. No hustle. Just systems that hold up under real use.</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><item><title><![CDATA[Over-Engineering as a Coping Mechanism]]></title><description><![CDATA[I needed to pick a speaker order. So I built a web app with six randomization engines. Here's what I actually learned.]]></description><link>https://letters.unrulycontext.com/p/over-engineering-as-coping-mechanism</link><guid isPermaLink="false">https://letters.unrulycontext.com/p/over-engineering-as-coping-mechanism</guid><dc:creator><![CDATA[adam]]></dc:creator><pubDate>Tue, 06 Jan 2026 03:41:32 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/0440ce84-84bb-4e44-9e18-b0e2226335b7_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I needed to decide the order of three speakers at an event.</p><p>Three people. All great. Any of them could go first, second, or third. There&#8217;s the usual caveat: the person who goes last is sometimes seen as the most important, but they also risk getting their time squeezed if earlier speakers run long. (Which, incidentally, is exactly what happened.)</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.unrulycontext.com/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">For generalists who build things. If that's you&#8212;or who you're becoming&#8212;subscribe.</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>These were people of equal seniority in this context. A simple decision. The kind of thing a normal person would resolve in thirty seconds.</p><p>But I&#8217;m neurospicy, and one of the things I&#8217;ve learned about my brain is that low-stakes decisions with no clear &#8220;right answer&#8221; are exactly where I get stuck. I&#8217;ll ruminate. I&#8217;ll weigh factors that don&#8217;t matter. I&#8217;ll think about it again tomorrow.</p><p>I didn&#8217;t want to do that. I wanted something slightly better than a coin toss&#8212;without having to think about how many coin tosses it takes to fairly order three items. (It&#8217;s more than you&#8217;d think, and now I&#8217;m already down a rabbit hole.)</p><p>So I did what any reasonable person would do: I built a web app with six different randomization visualization engines.</p><p>Meet <a href="https://randomatic3000.com/">RandoMatic 3000</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5W81!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b615317-16f5-4a37-8062-59af7c6b3233_1376x768.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5W81!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b615317-16f5-4a37-8062-59af7c6b3233_1376x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!5W81!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b615317-16f5-4a37-8062-59af7c6b3233_1376x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!5W81!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b615317-16f5-4a37-8062-59af7c6b3233_1376x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!5W81!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b615317-16f5-4a37-8062-59af7c6b3233_1376x768.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5W81!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b615317-16f5-4a37-8062-59af7c6b3233_1376x768.jpeg" width="1376" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2b615317-16f5-4a37-8062-59af7c6b3233_1376x768.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1376,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2211369,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://letters.unrulycontext.com/i/183617478?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b615317-16f5-4a37-8062-59af7c6b3233_1376x768.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5W81!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b615317-16f5-4a37-8062-59af7c6b3233_1376x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!5W81!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b615317-16f5-4a37-8062-59af7c6b3233_1376x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!5W81!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b615317-16f5-4a37-8062-59af7c6b3233_1376x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!5W81!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b615317-16f5-4a37-8062-59af7c6b3233_1376x768.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2><strong>The point isn&#8217;t the tool</strong></h2><p>Here&#8217;s the thing: I didn&#8217;t even use RandoMatic 3000 to make the speaker decision. By the time the tool was done, I&#8217;d already figured it out the old-fashioned way.</p><p>But now the tool exists. It&#8217;s live. It works. Other people have used it. And I practiced an entire zero-to-one workflow that I&#8217;ll use again on projects that actually matter.</p><p>This is the part that&#8217;s hard to explain to people who think building is about outcomes: sometimes the tool isn&#8217;t the point. The process is the point. The having-a-thing-that-exists is the point. The muscle memory of shipping is the point.</p><p>RandoMatic 3000 is aggressively over-engineered for what it does. Six visualization engines? Statistical trial mode? Dark/light mode toggle? For picking names out of a hat?</p><p>Yes. Because it was fun. Because constraints make projects interesting. And because I wanted to see if I could go from &#8220;vague idea&#8221; to &#8220;live on the internet&#8221; in a single working session using AI as my coding partner.</p><p>I could. Here&#8217;s how.</p><h2><strong>Start with the end, not the code</strong></h2><p>Before I wrote a single line of code&#8212;before I even opened a terminal&#8212;I spent time thinking through three things:</p><p><strong>1. Desired outcomes.</strong> What does &#8220;done&#8221; look like? In this case: a working web app that randomly orders or selects from a list of items, with some visual flair, accessible to anyone with the link.</p><p><strong>2. User stories.</strong> How will someone actually use this? They&#8217;ll land on a page, enter some items, pick a visualization style, and get a result. No accounts, no setup, no friction.</p><p><strong>3. Constraints.</strong> This is the most important part, and the one most people skip.</p><p>Constraints aren&#8217;t limitations&#8212;they&#8217;re <em>decisions made in advance</em> that prevent scope creep and make the project actually shippable. Here&#8217;s what I decided:</p><ul><li><p>Single-page web app. No multi-page routing.</p></li><li><p>No backend. Everything runs in the browser.</p></li><li><p>No login system. Anyone with the link can use it.</p></li><li><p>Single GitHub repository, deployed to Netlify.</p></li><li><p>HTML, CSS, JavaScript. React for the UI.</p></li><li><p>Test-driven development from the start.</p></li></ul><p>Each constraint closed a door. And every closed door made the project smaller, clearer, and more likely to actually get finished.</p><p>This isn&#8217;t a software-specific insight. It applies to anything you&#8217;re trying to get from zero to one: the clearer you are about what you&#8217;re <em>not</em> doing, the easier it is to do the thing you <em>are</em>doing.</p><h2><strong>Talk before you type</strong></h2><p>Once I had the constraints and outcomes clear in my head, I did something that might seem old-fashioned: I talked it out.</p><p>I use an app called MacWhisper&#8212;it runs OpenAI&#8217;s Whisper model locally and transcribes speech to text. I opened it, hit record, and just... talked through everything. The goals, the constraints, the user stories, the things I wasn&#8217;t sure about.</p><p>A few minutes of rambling became a text file. That text file became the context I fed to my AI coding tool.</p><p>This is one of the most important things I&#8217;ve learned about working with AI: <em>the quality of the context determines the quality of the output</em>. If you give an AI coding agent a vague prompt, you&#8217;ll get vague code. If you give it a detailed, thoughtful description of what you&#8217;re building and why, you&#8217;ll get something much closer to what you actually want.</p><p>Dictation is my way of getting the messy thinking out of my head and into a format the AI can use. It&#8217;s faster than typing, and it captures nuance I&#8217;d otherwise edit out.</p><h2><strong>The technical bit (feel free to skip)</strong></h2><p><em>If you&#8217;re not interested in the specifics of AI-assisted coding workflows, jump to the next section. The principles above and below are the transferable parts.</em></p><p>My AI coding setup for this project:</p><p><strong>Tool:</strong> Factory Droid (though Claude Code works similarly). I like Factory Droid because it gives me access to multiple models under one account&#8212;Claude Opus 4.5 for heavy lifting, Gemini Pro for UI polish, OpenAI Codex for quick fixes&#8212;and their context management is excellent. Long sessions don&#8217;t require constant re-prompting after context compression.</p><p><strong>Process:</strong></p><ol><li><p>Created a new directory, opened my terminal, launched the AI agent.</p></li><li><p>Pasted in my entire pre-specification dictation&#8212;goals, outcomes, constraints, user stories, everything.</p></li><li><p>Switched to <strong>Spec/Plan mode</strong>(Shift+Tab in Factory Droid, &#8220;Plan Mode&#8221; in Claude Code). This is crucial. In this mode, the AI researches and plans but doesn&#8217;t write code yet. You collaborate on the specification together.</p></li><li><p>Went back and forth several times on the spec. Each time the AI proposed a plan, I&#8217;d tweak it&#8212;clarifying epics, adjusting scope, adding constraints I&#8217;d forgotten. The goal is <em>painful clarity</em> before any code gets written.</p></li><li><p>Once the spec was solid, I approved it and let the AI start coding.</p></li></ol><p><strong>Why this matters:</strong> The spec phase is where most of the real work happens. I&#8217;d estimate a third of the total effort was pre-spec thinking, a third was spec refinement, and only the final third was actual coding and testing. Most people invert this ratio&#8212;they jump straight to code and wonder why projects get messy.</p><p><strong>On testing:</strong> I always use test-driven development, even for small projects. Here&#8217;s why: I don&#8217;t read every line of code the AI writes, but I <em>do</em> read every line of the tests. If the tests are well-written and they pass, I have high confidence the code is solid. Tests are my verification layer.</p><p><strong>On documentation:</strong> I keep an AGENTS.md file updated throughout the project. This makes it easy to switch models mid-session or pick up where I left off later. Good documentation is context you don&#8217;t have to re-explain.</p><h2><strong>The real work is testing</strong></h2><p>Here&#8217;s something that surprised me when I started working with AI coding tools: the coding part is actually kind of boring to watch. Files get created. Tests run. Servers spin up. It&#8217;s impressive the first few times, then it&#8217;s just... waiting.</p><p>The real work&#8212;the part that requires human judgment&#8212;is testing.</p><p>You have to test manually, as early as possible, as often as possible. You&#8217;ll find things that are completely broken, things that are subtly wrong, and things that technically work but feel off when you use them.</p><p>This is normal. This is how software gets built. The bugs aren&#8217;t failures; they&#8217;re the work revealing itself.</p><p>With RandoMatic 3000, the first bugs I found were UI issues. Elements in weird places. Layouts that didn&#8217;t make sense. I made a wireframe&#8212;and by &#8220;wireframe&#8221; I mean I drew a crude sketch on paper and took a photo&#8212;and showed it to the AI. Changes were made. Some tests broke. We fixed them.</p><p>Then I moved to end-to-end testing. I went to ChatGPT and asked for 15 different scenarios: &#8220;ways to pick the order for speakers at an event.&#8221; I dictated the context, got back a list of test cases&#8212;some good, some silly&#8212;and worked through them. Names that looked like code. Names in different languages. Edge cases that might break things.</p><p>Each round of testing surfaced more bugs. Each bug got fixed. This is the loop.</p><p>The great thing about AI as a coding partner: it doesn&#8217;t get tired, doesn&#8217;t get defensive, and doesn&#8217;t complain when you send something back for the fifth time. You can be as demanding as you need to be.</p><h2><strong>Ship before it&#8217;s perfect</strong></h2><p>When I felt reasonably good about the state of things, I pushed the code to GitHub and connected the repo to Netlify. A few minutes later, I had a live URL I could share.</p><p>I found more bugs immediately. Fixed them. Pushed again.</p><p>This is the part that trips people up: you have to ship before it&#8217;s perfect, because &#8220;perfect&#8221; is a state you discover through contact with reality, not through more planning.</p><p>RandoMatic 3000 isn&#8217;t perfect now. There are probably edge cases I haven&#8217;t thought of. Features I could add. Polish I could apply.</p><p>But it&#8217;s <em>done enough</em>. It exists. It works. People can use it.</p><p>That&#8217;s the bar for zero-to-one work: not &#8220;is it flawless?&#8221; but &#8220;does it exist and do the thing?&#8221;</p><h2><strong>What I actually learned</strong></h2><p>The tool was way more than I needed for a three-person speaker order decision. But building it taught me (or re-taught me) a few things:</p><p><strong>Constraints are gifts.</strong> Every door you close in advance is a decision you don&#8217;t have to make later. &#8220;No backend&#8221; and &#8220;no login&#8221; turned a potentially sprawling project into something I could finish in a day.</p><p><strong>The spec is the work.</strong> Two-thirds of the effort happened before any code was written. If you&#8217;re struggling to finish projects, you might be under-investing in the planning phase.</p><p><strong>AI is a partner, not a replacement.</strong> I read every test. I made the wireframe. I did the manual testing. I made all the judgment calls. The AI wrote code; I made decisions.</p><p><strong>Testing is where building actually happens.</strong> The first version is never right. The iteration loop&#8212;test, find bugs, fix, repeat&#8212;is the real process.</p><p><strong>Sometimes the tool isn&#8217;t the point.</strong>I didn&#8217;t use RandoMatic 3000 for the original decision. But I have the tool now, I practiced the workflow, and I have something to share. That&#8217;s three wins from one silly project.</p><h2><strong>The links</strong></h2><ul><li><p><a href="https://randomatic3000.com/">RandoMatic 3000</a> &#8212; try it yourself</p></li><li><p><a href="https://github.com/adamprime/randomatic3000">GitHub repo</a> &#8212; see how the sausage was made</p></li></ul><div><hr></div><h2><strong>One question for you</strong></h2><p>I&#8217;m curious what this sparks.</p><p>Maybe it&#8217;s a project you&#8217;ve been circling but haven&#8217;t started. Maybe it&#8217;s a dumb tool you&#8217;ve thought about building but couldn&#8217;t justify. Maybe it&#8217;s just the recognition that sometimes the thing you make isn&#8217;t the point&#8212;the making is.</p><p>What&#8217;s something you&#8217;ve been tempted to over-engineer? Or: what&#8217;s a small, silly thing you could build that would teach you something bigger?</p><p>Hit reply. I read everything.</p><p>adam</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.unrulycontext.com/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">If you made it this far, you&#8217;re probably my people. Subscribe and I&#8217;ll keep sending these.</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>