<?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[Curious Agents]]></title><description><![CDATA[Writing about my explorations in AI memory, retrieval, reflection and self-improvement loops]]></description><link>https://curiousagents.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!9FdV!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64652426-1c2f-4a9a-bb41-cd7d8063f2fc_120x120.png</url><title>Curious Agents</title><link>https://curiousagents.substack.com</link></image><generator>Substack</generator><lastBuildDate>Sat, 11 Apr 2026 00:12:26 GMT</lastBuildDate><atom:link href="https://curiousagents.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Tim Johnson]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[curiousagents@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[curiousagents@substack.com]]></itunes:email><itunes:name><![CDATA[Tim Johnson]]></itunes:name></itunes:owner><itunes:author><![CDATA[Tim Johnson]]></itunes:author><googleplay:owner><![CDATA[curiousagents@substack.com]]></googleplay:owner><googleplay:email><![CDATA[curiousagents@substack.com]]></googleplay:email><googleplay:author><![CDATA[Tim Johnson]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The Agent Memory Problem Nobody Is Solving]]></title><description><![CDATA[Switching to a new agent platform is getting easier.]]></description><link>https://curiousagents.substack.com/p/the-agent-memory-problem-nobody-is</link><guid isPermaLink="false">https://curiousagents.substack.com/p/the-agent-memory-problem-nobody-is</guid><dc:creator><![CDATA[Tim Johnson]]></dc:creator><pubDate>Fri, 03 Apr 2026 17:56:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9FdV!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64652426-1c2f-4a9a-bb41-cd7d8063f2fc_120x120.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Switching to a new agent platform is getting easier. Many new projects in this space are offering OpenClaw migration scripts too.</p><p>Hermes has <code>hermes claw migrate</code>. OpenFang has <code>openfang import --from openclaw</code>. The tooling is polished. The onboarding is smooth.</p><p>What neither of them migrates is the memory.</p><p>Not the memory of what tools you configured. Not the memory of what channels you set up. The other kind: six months of your agent learning how you think, what you value, what you&#8217;ve tried before, how you like to be talked to. The corrections you made when it got something wrong. The preferences it absorbed without you explicitly stating them. The context it accumulated one conversation at a time.</p><p>You can move your skills. You can&#8217;t move the relationship.</p><p>Every migration resets that to zero.</p><div><hr></div><h2>What the best implementations look like right now</h2><p>Before talking about what&#8217;s missing, it&#8217;s worth spending time on what Nous Research got right with Hermes.</p><p>Hermes ships with a five-layer memory architecture. Not a memory module. Five distinct, interconnected layers. I haven&#8217;t seen anything this complete in an open agent system.</p><p><strong>Layer 1: ContextCompressor.</strong> This handles the within-session problem: as conversations grow, context windows fill up and earlier content gets dropped. ContextCompressor doesn&#8217;t just truncate. It compresses using a structured template (Goal, Progress, Files, Decisions) and updates iteratively across compressions. The conversation stays coherent even as the raw history scrolls away.</p><p><strong>Layer 2: Honcho user modeling.</strong> This is the cross-session problem. Honcho builds and maintains a model of you across conversations using a dialectic Q&amp;A approach. It forms hypotheses about your preferences, tests them, and refines them. The &#8220;peer card&#8221; that comes out is searchable and composable. Your agent accumulates an actual model of who you are, not just a growing file of notes.</p><p><strong>Layer 3: Auto skill creation.</strong> When the agent solves a problem it hasn&#8217;t seen before, it has a mechanism to formalize that solution into a reusable skill. Experience compresses into capability. The longer you use it, the more it knows how to handle your particular workflows.</p><p><strong>Layer 4: FTS5 session search.</strong> All conversations are stored in SQLite with full-text search. You can ask &#8220;what did we decide about the API schema&#8221; and it finds the answer. This is something most agent systems treat as an afterthought. Hermes treats it as infrastructure.</p><p><strong>Layer 5: RL training pipeline.</strong> This is the one that surprised me most. Hermes saves interaction trajectories and can feed them into Atropos for model fine-tuning. The agent can initiate its own training runs. Not just memory, but a feedback loop that improves the underlying model from your actual usage patterns.</p><p>Taken together, this is a serious system. The people who built it thought carefully about what memory actually means for a long-lived agent relationship.</p><div><hr></div><h2>Observational Memory takes a different angle</h2><p>Mastra&#8217;s Observational Memory (OM) approaches the problem differently, and the benchmarks are worth looking at.</p><p>OM clocks roughly 95% on LongMemEval. Honcho (Hermes&#8217;s user modeling layer) hits around 90% on LongMem S with Haiku 4.5, and 88.8% on LongMem M at near one million tokens, with 89.9% on LoCoMo.</p><p>On the benchmark numbers alone, OM has an edge.</p><p>But comparing them directly misses the point. They&#8217;re solving different problems. OM is closest in function to Hermes&#8217;s ContextCompressor: it&#8217;s about compressing the conversation-part of the context, keeping the conversation coherent as a session grows in a simple (but also prompt-cachable) way. Honcho is doing something else: building a persistent model of you across sessions, understanding the person rather than just what has been said.</p><p>Both are valid. OM gives you better context compression for conversations that can stretch out almost infinitely. Hermes gives you both context compression and user modeling (you could argue that OM&#8217;s system includes these &#8220;user observations&#8221;, where Hermes separates them), plus search plus RL (if you care to run it) but the BIGGER addition is the auto-skill-creation and reflection. They&#8217;re not competing directly. They&#8217;re addressing overlapping pieces of a larger problem.</p><p>OM&#8217;s benchmarks show Hermes a clearly better way of doing compaction. But Hermes is clearly in the lead with thinking through these other mechanisms.</p><div><hr></div><h2>The wall you hit when you want to move</h2><p>Here&#8217;s where the practical problem shows up.</p><p>You&#8217;ve been using OpenClaw for 4 months. Your agent knows how you work. It knows you hate emdashes in blog posts. It knows you&#8217;re building something on Elixir and why. It knows your project naming conventions, your preferred tone, the context behind half a dozen ongoing threads. It knows things you didn&#8217;t explicitly tell it: patterns it picked up from watching you push back and correct and redirect over hundreds of conversations.</p><p>Then Hermes ships something compelling. Or OpenFang does. You want to try it.</p><p>You run <code>hermes claw migrate</code>. Your skills come over. Your configuration comes over. Your channel setup comes over.</p><p>Your agent&#8217;s model of you doesn&#8217;t.</p><p>The new system has no idea who you are. You&#8217;re back to day one of the relationship.</p><p>For someone who has invested seriously in an agent over months, this can be a real switching cost. We all want to be able to upgrade to better features/skills/tools. But sometimes the &#8220;familiar&#8221; gets in the way of the &#8220;new&#8221; and we don&#8217;t want to throw away all that rich context.</p><p>The more sophisticated the memory system, the higher the switching cost.</p><div><hr></div><h2>What&#8217;s missing: an open memory format</h2><p>There&#8217;s no standard for what an agent memory export should contain.</p><p>There&#8217;s no agreed-upon schema for the things that matter: user preferences, learned corrections, relationship context, projects in-flight, skill provenance. There&#8217;s no convention for how a receiving system should ingest that data and make it usable.</p><p>ContextCompressor and OM can&#8217;t share a memory state because there&#8217;s no common format for what a &#8220;compressed context&#8221; looks like across systems. Honcho&#8217;s peer cards live inside Hermes&#8217;s SQLite schema. OpenClaw&#8217;s memories live in daily markdown files and whatever ad-hoc files it wants to create for specific memories in it&#8217;s folder.</p><p>Every system right now is inventing its own answer to the memory problem in isolation.</p><p>A common memory interchange format doesn&#8217;t need to solve every problem at once. It needs to answer a few core questions: what does a user model export contain? What does conversation history look like in a format another agent can consume? How does a receiving system signal what it can and can&#8217;t use?</p><p>These are solvable problems. Maybe the OM format is a good starting-point to pick from (due to it&#8217;s high-scores) but I do like the addition of the peer-card from Hermes. Do we need to keep raw-logs as backup for search-ability? JSONL would seem like a fine candidate for that as a secondary preference.</p><p>If you&#8217;re working on agent memory, building an agent platform, or thinking about this problem from a standards perspective, I&#8217;d like to hear from you. </p><p>The conversation needs to start somewhere.</p>]]></content:encoded></item><item><title><![CDATA[Experiments in Building an Automatic Software Factory]]></title><description><![CDATA[My project cc-pipeline, what it unlocks for building from scratch, massive re-writes, and lessons.]]></description><link>https://curiousagents.substack.com/p/experiments-in-building-an-automatic</link><guid isPermaLink="false">https://curiousagents.substack.com/p/experiments-in-building-an-automatic</guid><dc:creator><![CDATA[Tim Johnson]]></dc:creator><pubDate>Thu, 26 Feb 2026 16:11:18 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!NfKE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91bbb295-6712-42f7-a80b-403ef99caa41_666x490.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Here&#8217;s a thing you can do in 2026: write a plain-English description of software you want built, run one command, go to bed, and wake up to a working implementation. Full SLDC, spec writing, unit and end-to-end test suite passing, git committed, phase by phase.</p><p>(to not bury the lead) here is the repo: <a href="https://github.com/timothyjoh/cc-pipeline">https://github.com/timothyjoh/cc-pipeline</a></p><p>That&#8217;s the pitch. Now here&#8217;s the honest version.</p><p>It works. Sometimes really well. But what it <em>actually</em> produces is determined almost entirely by what you put in. Leave something unspecified and the pipeline will make a decision for you &#8212; and that decision might be &#8220;functional but ugly&#8221; or &#8220;mechanics intact, polish missing.&#8221; The factory metaphor holds: garbage in, garbage out. But with a good spec? The output is genuinely impressive.</p><p>This is the story of how I built that pipeline, what I learned from running it a dozen times on projects ranging from an Elixir port to a Kirby platformer, and why I think building your own is more approachable than you&#8217;d expect.</p><div><hr></div><h2>2025: Babysitting the Context Window</h2><p>I spent most of 2025 deep in spec-driven development frameworks. The premise was compelling: instead of chatting at an LLM, you give it a full specification and let it execute against that spec. Several frameworks were doing interesting things here.</p><p><strong><a href="https://github.com/bmadcode/BMAD-METHOD">BMAD Method</a></strong> gave you a structured way to think about AI-assisted development with roles and phases. <strong><a href="https://github.com/jmanhype/speckit">GitHub&#8217;s Speckit</a></strong> explored spec-first workflows. <strong><a href="https://openspec.dev/">OpenSpec</a></strong> took a similar angle. <strong><a href="https://github.com/obra/superpowers">Obra&#8217;s Superpowers</a></strong>  was doing interesting things with structured AI workflows. But my favorite approach was <strong>HumanLayer&#8217;s <a href="https://github.com/humanlayer/humanlayer/tree/main/.claude/commands">three-step research &#8594; plan &#8594; implement process</a></strong>, Dex&#8217;s talks about not-anthropomorphizing matched my intuition about how to break down work cleanly.</p><p>The frameworks were working where the models had poor performance in 2025. It was easy to use, but I kept wondering &#8220;can I automate some of this?&#8221;. Every step required manual intervention. After Claude finished a spec, I had to review/edit the output, start a new context, invoke the next command, and wait. Review it again, ask for fixes. And above all we always had to fix the tests that were over-simplistic, and involved too much mocking.</p><p>While it was all easier than ever, the disconnect between waiting 30-40 minutes at each stage and coming back was a huge cognitive disconnect. I wasn&#8217;t building software. I was babysitting a context window between gaps in the workday. While this enabled me to be productive with my overly meeting-heavy days, it was still disjointed.</p><p>When Anthropic shipped subagents and then Claude Agent Teams, something clicked. Here was a way to have Claude orchestrate its own work across multiple contexts. I spent a week with tmux and Agent Teams, spinning up coordinated multi-agent sessions. The results were promising enough that I made a decision: I was going to automate the SDLC loop itself &#8212; not just the build step, but the whole cycle: spec &#8594; research &#8594; plan &#8594; build &#8594; review &#8594; fix &#8594; reflect &#8594; commit. I was going to &#8220;live with&#8221; the agent to make decisions between the phases that I might otherwise be around to make, and then I could come back and correct it later. And I was going to add my own gates &#8212; testing passes, reflection checkpoints, a staff-engineer-level code review at each phase. The need was &#8220;while I am away, keep building&#8221;, then I can come back to something to react-to, and we can start another cycle of correction and polish.</p><p>That decision is what became <strong><a href="https://github.com/timothyjoh/cc-pipeline">cc-pipeline</a></strong>.</p><div><hr></div><h2>The First Test: Porting OpenClaw to Elixir/BEAM</h2><p>The first real question wasn&#8217;t &#8220;can the pipeline build something new?&#8221; It was &#8220;can the pipeline take an existing, non-trivial codebase and rewrite it in a different language?&#8221;</p><p>I&#8217;d already written about attempting this on a company project (<a href="https://curiousagents.substack.com/">see my previous post on Substack</a>) with moderate success. I tried an automatic approach using subagents and agent teams, and while it announced &#8220;Success, it is done&#8221;, my savvy readers will know better than to trust Claude on a multi-hour run that it did everything it was asked.</p><p>The target for the pipeline test was ambitious: porting <a href="https://github.com/openclaw/openclaw">OpenClaw</a> &#8212; the open-source AI gateway I run my own agent on &#8212; to Elixir and the BEAM platform. This wasn&#8217;t random. I&#8217;ve been circling Elixir for years. The BEAM VM&#8217;s model of millions of lightweight processes, supervision trees, and fault tolerance feels architecturally right for agentic systems. AI eliminates Elixir&#8217;s historical barrier (hard to hire for, less training on LLMs), and what remains are its architectural advantages.</p><div><hr></div><h2>Shell Loops, tmux Hell, and the Agent SDK</h2><p>The earliest version of the pipeline was a bash script. A loop over phases, with a call to <code>claude -p</code> at most steps. Pipe the spec in, capture the output, write it to disk, move to the next step. It worked, easily I might add.</p><p>The first real problem: some steps need Claude Code&#8217;s interactive mode. The review and build steps in particular benefit from Claude having full filesystem access, access to the project&#8217;s CLAUDE.md and any custom skills you want to add, the ability to run commands, write and execute tests. <code>claude -p</code> is non-interactive, it takes a prompt and returns output, like a function call. But <code>claude</code> (interactive) is a full REPL session. </p><p>The first users of Claude Agent Teams said the answer was tmux. Launch a tmux session, start <code>claude</code> in it, send the prompt via <code>send-keys</code> or <code>paste-buffer</code>, wait for it to finish, detect completion, exit cleanly. Sounds reasonable.</p><p>The timing problems alone were maddening. <code>send-keys</code> would fire before the Claude session was fully initialized and the prompt would vanish. Or it would land but never submit. <code>paste-buffer</code> had truncation issues with long prompts. Detecting <em>completion</em> was even harder, there&#8217;s no clean signal when Claude Code is done with a task, so I was polling for sentinel files, watching for specific output patterns, putting &#8220;wait&#8221; timers all over the place.</p><p>And then getting Claude to <em>exit cleanly</em> to reset the context (which is the whole point, a fresh context window per step) that was its own adventure. Send <code>/exit</code>. Wait. Send Escape. Wait. Send Enter. Hope. Repeat.</p><p>I burned days on this. The tmux approach never got reliable enough to trust overnight.</p><p>The solution was staring at me the whole time, and it was the <strong>Claude Agent SDK</strong>. Instead of trying to automate an interactive terminal session, I could control Claude Code programmatically: pipe the prompt to stdin, capture structured output from stdout, and get a clean process exit when the work is done. Each pipeline step gets a fresh context window, automatically. No timing hacks, no tmux polling, no sentinel files. AND the Agent SDK allows me to use my Claude Max subscription, because it is not harnessing the API directly, but through Claude Code CLI.</p><p>And with structured output came structured logging. Which meant I could build a <strong>TUI</strong> &#8212; a terminal dashboard showing which phase and step is running, recent events, progress through the workflow. Instead of a black box running overnight, you can actually watch it work. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NfKE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91bbb295-6712-42f7-a80b-403ef99caa41_666x490.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NfKE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91bbb295-6712-42f7-a80b-403ef99caa41_666x490.png 424w, https://substackcdn.com/image/fetch/$s_!NfKE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91bbb295-6712-42f7-a80b-403ef99caa41_666x490.png 848w, https://substackcdn.com/image/fetch/$s_!NfKE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91bbb295-6712-42f7-a80b-403ef99caa41_666x490.png 1272w, https://substackcdn.com/image/fetch/$s_!NfKE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91bbb295-6712-42f7-a80b-403ef99caa41_666x490.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NfKE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91bbb295-6712-42f7-a80b-403ef99caa41_666x490.png" width="666" height="490" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/91bbb295-6712-42f7-a80b-403ef99caa41_666x490.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:490,&quot;width&quot;:666,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:65909,&quot;alt&quot;:null,&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://curiousagents.substack.com/i/189260567?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91bbb295-6712-42f7-a80b-403ef99caa41_666x490.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NfKE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91bbb295-6712-42f7-a80b-403ef99caa41_666x490.png 424w, https://substackcdn.com/image/fetch/$s_!NfKE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91bbb295-6712-42f7-a80b-403ef99caa41_666x490.png 848w, https://substackcdn.com/image/fetch/$s_!NfKE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91bbb295-6712-42f7-a80b-403ef99caa41_666x490.png 1272w, https://substackcdn.com/image/fetch/$s_!NfKE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91bbb295-6712-42f7-a80b-403ef99caa41_666x490.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">Phase 17 TUI during the build of Kirby your Enthusiasm</figcaption></figure></div><p></p><div><hr></div><h2>The Experiments</h2><h3>Swimlanes &#215; 2</h3><p>I built the <a href="https://github.com/timothyjoh/swimlanes">Swimlanes</a> project twice &#8212; once in Astro 5 with React islands and SQLite, once in <a href="https://github.com/timothyjoh/rails-swimlanes">Ruby on Rails</a>. Both times from the same basic concept: a Trello-like kanban board for taking notes, simple.</p><p>Both runs produced functional software. Solid test coverage, drag-and-drop working, data persistence, the whole spec. If you squinted at it as a backend engineer, it was fine.</p><p>The UI was rough. Not broken, but <em>developer-designed</em>. Both implementations had that slightly-off quality of software that was never told what it should look like. Which makes sense, because we never told it to use a design framework or UI library beyond specifying tailwind CSS. The BRIEF.md specified features and data model but said nothing about design system, component library, visual style, or aesthetic direction.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XHkO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F700e99e7-ade7-438a-ba6b-afcdd27999bb_1316x794.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XHkO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F700e99e7-ade7-438a-ba6b-afcdd27999bb_1316x794.png 424w, https://substackcdn.com/image/fetch/$s_!XHkO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F700e99e7-ade7-438a-ba6b-afcdd27999bb_1316x794.png 848w, https://substackcdn.com/image/fetch/$s_!XHkO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F700e99e7-ade7-438a-ba6b-afcdd27999bb_1316x794.png 1272w, https://substackcdn.com/image/fetch/$s_!XHkO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F700e99e7-ade7-438a-ba6b-afcdd27999bb_1316x794.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XHkO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F700e99e7-ade7-438a-ba6b-afcdd27999bb_1316x794.png" width="1316" height="794" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/700e99e7-ade7-438a-ba6b-afcdd27999bb_1316x794.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:794,&quot;width&quot;:1316,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:71507,&quot;alt&quot;:null,&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://curiousagents.substack.com/i/189260567?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F700e99e7-ade7-438a-ba6b-afcdd27999bb_1316x794.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XHkO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F700e99e7-ade7-438a-ba6b-afcdd27999bb_1316x794.png 424w, https://substackcdn.com/image/fetch/$s_!XHkO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F700e99e7-ade7-438a-ba6b-afcdd27999bb_1316x794.png 848w, https://substackcdn.com/image/fetch/$s_!XHkO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F700e99e7-ade7-438a-ba6b-afcdd27999bb_1316x794.png 1272w, https://substackcdn.com/image/fetch/$s_!XHkO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F700e99e7-ade7-438a-ba6b-afcdd27999bb_1316x794.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">Swimlanes the Astro version</figcaption></figure></div><p>The lesson wrote itself: <strong>if you don&#8217;t specify the design, the pipeline designs something for you.</strong> And &#8220;something&#8221; is not the same as &#8220;good.&#8221; A single line in the brief &#8212; &#8220;use Tailwind with the Shadcn component library, clean minimal aesthetic with neutral grays&#8221; &#8212; would have changed the output dramatically.</p><h3>Sales Performance Statistics in R</h3><p>This one I&#8217;m proud of, partly because it surprised me.</p><p>I&#8217;ve never written R in my life. I know what it is, I know roughly what it does, I&#8217;ve never typed an R expression. The brief was simple: given a set of sales rep performance data, build a statistical analysis and a formatted report.</p><p>I co-wrote the BRIEF.md with Claude &#8212; iterated on what &#8220;sales performance analysis&#8221; should actually mean, what metrics mattered, what the report should communicate. Then kicked off the pipeline and walked away.</p><p>It generated its own dummy data, ran the statistical calculations, and designed a report layout. When I came back, I had a working R project &#8212; reproducible, documented, producing output that looked like what I&#8217;d described. I didn&#8217;t struggle with the language. I didn&#8217;t have to learn the ecosystem. I described what I wanted and the pipeline figured out the R-specific implementation details.</p><p>That&#8217;s the part that&#8217;s hard to communicate until you&#8217;ve seen it: <strong>domain knowledge barriers dissolve when the spec is clear.</strong> You don&#8217;t need to know R to get R code. You need to know what you want.</p><h3>Tetris &#215; 2</h3><p>Tetris was the control experiment. Two runs, identical BRIEF.md, different pipeline runs. </p><p>Play it here:  <a href="https://tetris-3d-pipelined.vercel.app/">https://tetris-3d-pipelined.vercel.app/</a></p><p>Code here: <a href="https://github.com/timothyjoh/tetris-3d-pipelined">https://github.com/timothyjoh/tetris-3d-pipelined</a></p><p>The results were slightly divergent. Not dramatically &#8212; both games were recognizably Tetris, both had the core mechanics, both ran in the browser. But small differences emerged: slightly different scoring logic, slightly different color palette, slightly different keyboard handling. Nothing alarming. Nothing that suggested the pipeline was unreliable.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NI3G!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef5051f-5ee6-4473-bdd3-3ab0069f2a70_1312x1172.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NI3G!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef5051f-5ee6-4473-bdd3-3ab0069f2a70_1312x1172.png 424w, https://substackcdn.com/image/fetch/$s_!NI3G!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef5051f-5ee6-4473-bdd3-3ab0069f2a70_1312x1172.png 848w, https://substackcdn.com/image/fetch/$s_!NI3G!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef5051f-5ee6-4473-bdd3-3ab0069f2a70_1312x1172.png 1272w, https://substackcdn.com/image/fetch/$s_!NI3G!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef5051f-5ee6-4473-bdd3-3ab0069f2a70_1312x1172.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NI3G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef5051f-5ee6-4473-bdd3-3ab0069f2a70_1312x1172.png" width="1312" height="1172" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bef5051f-5ee6-4473-bdd3-3ab0069f2a70_1312x1172.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1172,&quot;width&quot;:1312,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:124648,&quot;alt&quot;:null,&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://curiousagents.substack.com/i/189260567?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef5051f-5ee6-4473-bdd3-3ab0069f2a70_1312x1172.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NI3G!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef5051f-5ee6-4473-bdd3-3ab0069f2a70_1312x1172.png 424w, https://substackcdn.com/image/fetch/$s_!NI3G!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef5051f-5ee6-4473-bdd3-3ab0069f2a70_1312x1172.png 848w, https://substackcdn.com/image/fetch/$s_!NI3G!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef5051f-5ee6-4473-bdd3-3ab0069f2a70_1312x1172.png 1272w, https://substackcdn.com/image/fetch/$s_!NI3G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef5051f-5ee6-4473-bdd3-3ab0069f2a70_1312x1172.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">Tetris first version</figcaption></figure></div><p>My read on why it worked so well: Tetris is one of the most-implemented games in history. Every LLM has seen hundreds of Tetris implementations in its training data. The shape of the problem is well-understood. This matters more than people realize. When you give the pipeline a well-known problem with clear mechanics, it has deep pattern-matching to draw on. The brief is almost a formality.</p><p>Which is also a warning: <strong>the pipeline&#8217;s ceiling is not the pipeline, it&#8217;s the training data PLUS the specifications you give it.</strong> Give it a well-documented problem and it flies. Give it something novel or ambiguous and it&#8217;ll still build something, albeit you will put in more work later.</p><h3>Kirby Your Enthusiasm</h3><p>This was the ambitious one. A 2D platformer starring Kirby as Larry David, navigating LA street encounters in the style of <em>Curb Your Enthusiasm</em>. Full Phaser 3, TypeScript, three acts, character absorb mechanics, Curb NPC dialogue encounters. The brief was detailed and the concept was delightful.</p><p>Repo: <a href="https://github.com/timothyjoh/kirby-your-enthusiasm">https://github.com/timothyjoh/kirby-your-enthusiasm</a></p><p>Here&#8217;s the honest report: the mechanics mostly work. Kirby moves. Kirby floats. The inhale mechanic functions. The act structure is there.</p><p>The look is rough. Kirby is a pink circle. The enemies are rectangles. The backgrounds are solid colors. It looks like a prototype demo, not a game you&#8217;d actually play.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xgkL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F964b0802-a6c3-4f2a-b496-8450aa91ced3_946x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xgkL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F964b0802-a6c3-4f2a-b496-8450aa91ced3_946x768.png 424w, https://substackcdn.com/image/fetch/$s_!xgkL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F964b0802-a6c3-4f2a-b496-8450aa91ced3_946x768.png 848w, https://substackcdn.com/image/fetch/$s_!xgkL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F964b0802-a6c3-4f2a-b496-8450aa91ced3_946x768.png 1272w, https://substackcdn.com/image/fetch/$s_!xgkL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F964b0802-a6c3-4f2a-b496-8450aa91ced3_946x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xgkL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F964b0802-a6c3-4f2a-b496-8450aa91ced3_946x768.png" width="946" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/964b0802-a6c3-4f2a-b496-8450aa91ced3_946x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:946,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19970,&quot;alt&quot;:null,&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://curiousagents.substack.com/i/189260567?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F964b0802-a6c3-4f2a-b496-8450aa91ced3_946x768.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xgkL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F964b0802-a6c3-4f2a-b496-8450aa91ced3_946x768.png 424w, https://substackcdn.com/image/fetch/$s_!xgkL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F964b0802-a6c3-4f2a-b496-8450aa91ced3_946x768.png 848w, https://substackcdn.com/image/fetch/$s_!xgkL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F964b0802-a6c3-4f2a-b496-8450aa91ced3_946x768.png 1272w, https://substackcdn.com/image/fetch/$s_!xgkL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F964b0802-a6c3-4f2a-b496-8450aa91ced3_946x768.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">Kirby at the final boss during phase 16 of the build (8 am the day after)</figcaption></figure></div><p>Part of this is inherent to the problem: game art is hard to specify in a text brief. But part of it is solvable. The pipeline&#8217;s architecture supports additional steps and for game development, one obvious next step would be a <strong>design phase that hands off to an image-capable model</strong> (Gemini?) to generate sprites and background assets before the build step runs. We haven&#8217;t built that yet. When we do, I expect Kirby will look a lot more like Kirby.</p><p>The Kirby experiment also surfaced something important about ambitious projects: the pipeline is <strong>far</strong> better than vibe-coding, but it&#8217;s not magic. A sophisticated, well-structured SDLC running through Claude Agent Teams can still produce a rough first pass on a complex, underspecified project. The tool amplifies your judgment, it doesn&#8217;t replace it. A professional who leans in, steers the brief toward the hard decisions, and treats the pipeline output as a strong starting point will get dramatically better results than someone who hands it a vague concept and hopes.</p><div><hr></div><h2>How cc-pipeline Works</h2><p>The idea is simple enough to explain in three steps.</p><p><strong>First: init.</strong> Run <code>npx cc-pipeline@latest init</code> in an empty repo. It scaffolds a <code>.pipeline/</code> directory with prompt templates, a <code>workflow.yaml</code> defining the step sequence, and a <code>BRIEF.md.example</code> to show you what a good brief looks like.</p><p><strong>Second: write the brief.</strong> Open Claude Code in the project and have a conversation:</p><pre><code><code>Using the @BRIEF.md.example as a template, let's discuss this project's goals
and write a BRIEF.md. Ask me for a quick description first, then ask questions
one-at-a-time to build a good brief.</code></code></pre><p>Claude asks you questions. You answer. The brief writes itself. This step matters more than any other. The better the brief, the better everything downstream.</p><p><strong>Third: run it and walk away.</strong></p><pre><code><code>npx cc-pipeline run</code></code></pre><p>Each phase runs through the same sequence of steps: <strong>spec &#8594; research &#8594; plan &#8594; build &#8594; review &#8594; fix &#8594; reflect &#8594; status &#8594; commit </strong>(or add your own). The review step runs a staff-engineer-level critique of the code, I prefer to use <code>codex</code> at this phase, it outputs a REVIEW.md and a MUST-FIX.md file. The fix step addresses any must-fix findings. The reflect step looks back at the phase and plans the next one. Status updates <code>STATUS.md</code> at the project root &#8212; a running summary of what&#8217;s been built, test coverage, and what&#8217;s coming. Then a git commit.</p><p>Watch the TUI if you want to see it in motion. Or just read <code>STATUS.md</code> &#8212; it&#8217;s one of the genuinely fun parts of running the pipeline, watching it document its own progress as it goes.</p><p><strong>Don&#8217;t miss this: it&#8217;s almost entirely customizable.</strong> The steps are defined in <code>.pipeline/workflow.yaml</code>. The prompts are markdown files in <code>.pipeline/prompts/</code>. You can add steps, remove steps, reorder them. Want a web research step before build to pull in current documentation? Add it. Want an extra test validation pass after fix? Add it. Want a dedicated design spec step that enforces a component library? Add it. Want to swap out CLIs that execute the steps, also easy.</p><p>The pipeline currently includes a built-in agent for Codex as well as the Claude Code agents. I personally run this using my $30/month ChatGPT subscription for the Codex-powered steps, and my Claude Max subscription for everything else. It&#8217;s not expensive (10% of my weekly plan for Claude), and you can mix and match however your subscriptions line up.</p><div><hr></div><h2>The Lesson</h2><p>The most important thing I learned across all these experiments can be compressed to one sentence:</p><p><strong>If you leave it unspecified in the brief, it will be handled in a way you didn&#8217;t choose.</strong></p><p>Sometimes that&#8217;s fine &#8212; the pipeline makes defaults based on the popularity of the LLM&#8217;s training data. </p><p>The inverse is also true: cc-pipeline is a genuinely excellent <strong>greenfield starting point</strong> for any project that&#8217;s roughly defined but not fully specified. Run it, get a solid foundation, then iterate. The output of Phase 1 is already more coherent than most &#8220;let me just start coding and see what happens&#8221; projects. The test suite is there from day one. The code review caught real issues. The architecture reflects the brief. I&#8217;ve been able to build some internal tooling here at my work that otherwise would have been a beast to build. Maybe this will be the start of your &#8220;I need my own custom CRM&#8221; application dreams.</p><p>Where it really shines is <strong>migrations and ports</strong>. &#8220;Take this open-source project, keep the A and B parts, drop X Y Z, keep it lightweight&#8221; &#8212; feed that as a brief, point it at the source repo as a research resource, and the pipeline will not only produce the implementation but will document <em>why</em> it made each architectural decision in the DECISIONS.md and STATUS.md it generates. You learn the codebase by watching it get rebuilt.</p><p>The BEAM experiment is my favorite example. I didn&#8217;t just end up with an Elixir port. I ended up with a running record of every design decision the pipeline made, in its own voice, at each phase. Reading it is like having a senior Elixir engineer narrate the architecture choices in real time.</p><div><hr></div><h2>The Invitation</h2><p>The repo is at <strong><a href="https://github.com/timothyjoh/cc-pipeline">github.com/timothyjoh/cc-pipeline</a></strong>. MIT licensed. Start with <code>npx cc-pipeline@latest init</code>.</p><p>If you want to use it as-is, go for it. Write a brief, run the pipeline, see what comes out.</p><p>If you want to build your own,<em> that&#8217;s the point</em>. The pattern is simple: a loop over phases, with a configurable set of steps, and a prompt template at each step. The intelligence lives in the prompts and the brief. The engine is just plumbing. You could build a version of this in a weekend that&#8217;s tuned exactly to how your team works, your own SDLC, your review criteria, your testing standards, your design system enforcement.</p><p>The factory is more approachable than it looks. You just have to decide what it should build, and tell it so.</p><p>I can&#8217;t wait to see what others derive from this, and what they ship. Please leave me a message on Twitter at https://x.com/timojhnsn if you find this useful.</p><p></p>]]></content:encoded></item><item><title><![CDATA[12 Hours vs. 2 Weeks: What I Learned Rewriting an App With AI]]></title><description><![CDATA[My re-write failed to achieve my goals, but it taught me more about the practice of writing software than I would have expected.]]></description><link>https://curiousagents.substack.com/p/12-hours-vs-2-weeks-what-i-learned</link><guid isPermaLink="false">https://curiousagents.substack.com/p/12-hours-vs-2-weeks-what-i-learned</guid><dc:creator><![CDATA[Tim Johnson]]></dc:creator><pubDate>Wed, 11 Feb 2026 23:48:21 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9FdV!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64652426-1c2f-4a9a-bb41-cd7d8063f2fc_120x120.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You inherited a codebase you didn&#8217;t write. The stack isn&#8217;t yours. The architecture works, but it&#8217;s held together with REST, webhooks, glue and cloud duct tape.</p><p>Sound familiar?</p><p>I spent a weekend rewriting a Python FastAPI backend into a completely new framework using Claude Code as my co-pilot. The whole thing took about 12 hours. Without AI, it would have taken two weeks minimum.</p><p>But here&#8217;s the twist: I&#8217;m not shipping it.</p><p>This post covers exactly what happened: the method that made it possible, the framework that almost won me over, and why &#8220;not shipping it&#8221; doesn&#8217;t mean the weekend was wasted.</p><p>Here&#8217;s what you&#8217;ll learn:</p><ul><li><p>The <strong>documentation-first method</strong> that makes AI-assisted rewrites actually work</p></li><li><p><strong>Three modes of AI-assisted development</strong> (I shy away from vibe-coding, and you should too)</p></li><li><p>An honest review of a promising framework that isn&#8217;t ready yet</p></li><li><p>Why the real value of my &#8220;failed&#8221; rewrite is the confidence that I can do this again easily, not the code</p><p></p></li></ul><h2>The Architecture That Worked&#8230; Until It Didn&#8217;t</h2><p>The existing system was a FastAPI service paired with an AI bot built on a Python agentic framework. They were glued together with REST requests and orchestrated through AWS Fargate tasks.</p><p>It worked. Requests came in, jobs ran, the AI did its thing.</p><p>But I couldn&#8217;t <em>see</em> any of it.</p><p>When errors were piling up and bug reports were coming&#8230; I was flying blind. There was no way to trace an incoming request from beginning to end. No unified view of what the background jobs were doing. No observability without bolting on yet another tool.</p><p>I wanted one thing: <strong>end-to-end request tracing without adding another framework to the pile</strong>.</p><p>That&#8217;s when I found <a href="https://motia.dev">motia.dev</a>.</p><p></p><h2>One Primitive to Replace Ten Frameworks</h2><p>Motia makes a bold promise: replace your APIs, background jobs, queues, workflows, and AI agent orchestration mixed with with a simple primitive called a &#8220;Step.&#8221;</p><p>A Step is just a file with a config and a handler. Motia auto-discovers these files and wires them together through an event-driven architecture. Think of it like this: <strong>Steps are to backends what React components are to frontends.</strong></p><p>Three things sold me:</p><p>1. <strong>Multi-language support.</strong> Each Step can be TypeScript or Python. I could rewrite the API and workflow layer in TypeScript while keeping the AI agents in Python and ADK. No compromises.</p><p>2. <strong>Built-in observability.</strong> Motia ships with bbservability built-in (called a Workbench), a visual dashboard that shows flow diagrams, request traces, state, and logs. Locally. Out of the box. No setup.</p><p>3. <strong>Event-driven by default.</strong> Steps communicate through emit and subscribe. Background jobs, queues, and retries are handled automatically. No Fargate tasks. No manual queue infrastructure.</p><p>It&#8217;s like the benefits of a share-nothing, event-driven architecture, but you can develop fast, run locally and work with it like your favorite simple monolith. <strong>SOLD!</strong></p><p></p><h2>The First 5 Hours: Zero Lines of Code</h2><p>Here&#8217;s the part most people skip&#8230; and it&#8217;s the reason the rewrite worked at all.</p><p>I didn&#8217;t write a single line of code in the first phase. Instead, I spent 2-3 full context windows having Claude Code <strong>reverse-engineer the existing codebase</strong>.</p><p>Why? Because I didn&#8217;t write this code. I didn&#8217;t know it intimately. Before I could port anything, I needed to <em>grok</em> it.</p><p>Here&#8217;s what we produced:</p><ul><li><p><strong>Mermaid diagrams</strong> of the system architecture</p></li><li><p><strong>Logic flows</strong> for each major feature</p></li><li><p><strong>Data flow maps</strong> showing how requests moved through the system</p></li><li><p><strong>Component descriptions</strong> for every key module</p></li></ul><p>I followed this critical path: I fed all of that documentation plus Motia&#8217;s LLM-friendly docs into Claude Code and asked it to build a migration plan.</p><p>The AI didn&#8217;t just have the source code. It had a mental model of the system.</p><p>This is the <strong>documentation-first</strong> method: Build the AI&#8217;s knowledge base before you ask it to build anything. Don&#8217;t ever start by letting the LLM write code immediately. Resist that urge.</p><p>The documentation phase took about 5 hours. I wanted to be thorough. It saved me days. Why? Because I now had the right mental model to prompt and steer the next steps.</p><p></p><h2>Three Ways to Work With AI (when to use each)</h2><p>Over the weekend, I naturally fell into three distinct modes of working with Claude Code. Each serves a different purpose.</p><h3>1. Vibe Coding: For Small, Specific Fixes</h3><p>This is the &#8220;just fix it&#8221; mode. You see a bug, you describe it, and the AI dives right into fix-it mode.</p><p>&#8220;This event handler isn&#8217;t emitting the right topic. [PASTE the wrong event]&#8221;</p><p>&#8220;Refactor this function to match the pattern in the other Steps.&#8221;</p><p>&#8220;The response schema is wrong: it&#8217;s missing X and Y properties.&#8221;</p><p><strong>When to use it:</strong> Small, contained changes where the context is obvious. Don&#8217;t use it for anything architectural.</p><h3>2. Structured Prompting: For Major Features</h3><p>For the initial rewrite and the testing phase, I used a four-step sequence I picked up (mostly) from <a href="https://x.com/dexhorthy">Dex Horthy</a> (watch his AI Engineer conference talks, follow the path):</p><ol><li><p><strong>Research:</strong> Have the AI analyze the relevant code and docs</p></li><li><p><strong>Planning:</strong> Ask it to propose an approach before writing anything</p></li><li><p><strong>Implementation:</strong> Execute the plan</p></li><li><p><strong>Validation:</strong> Verify the output against requirements</p></li></ol><p>This is slower than vibe coding. It&#8217;s also dramatically more reliable for anything complex, a brownfield codebase or anything you want to build right.</p><p>Code:</p><p><a href="https://github.com/humanlayer/claudelayer/tree/main/.claude/commands">https://github.com/humanlayer/claudelayer/tree/main/.claude/commands</a></p><p>The major usage is <code>/research_codebase</code>, <code>/create_plan</code>, <code>/implement_plan</code> in that order. I have added to it my own testing plans which vary from project to project, which include unit, end-to-end and some performance benchmarking</p><p><strong>When to use it:</strong> Epics, major features, migrations, refactoring, anything that touches multiple files or systems.</p><h3>3. Skill Building: For Institutional Knowledge</h3><p>This one surprised me. After correcting Claude Code on a pattern a few times, I started asking it to &#8220;codify the things you learned in this session, and the corrections I gave you into a reusable skill&#8221; (stored directly in the <code>/.claude/skills</code> directory in the project).</p><p>Now those patterns live in the codebase. Future developers (and future coding agents) get them automatically when needed.</p><p><strong>When to use it:</strong> Any time you find yourself correcting the AI on the same type of mistake twice. Anytime you watch the AI spin out and devour tokens trying things over and over.</p><p></p><h2>The Weekend Sprint: What 12 Hours of AI Pair Programming Looks Like</h2><p>Here&#8217;s how the actual work broke down:</p><h3>Phase 1: The Initial Port (5 hours)</h3><p>With the documentation and migration plan in hand, Claude Code scaffolded the Motia Steps from the existing FastAPI routes. API endpoints became API Steps. Background Fargate tasks became Event Steps. Scheduled jobs became Cron Steps.</p><p>The AI made a solid first pass. Not perfect, but a legitimate, running application.</p><h3>Phase 2: Gap Analysis (3-4 hours)</h3><p>This is where the real work happened. We wrote integration tests and end-to-end tests, and they flushed out everything Claude Code missed.</p><p>Edge cases. Error handling. Subtle business logic that didn&#8217;t make it through the port.</p><p><strong>Lesson:</strong> The first pass is a draft. Tests are what turn it into production code. Don&#8217;t skip this phase: it&#8217;s where you catch the elusive bugs.</p><h3>Phase 3: Improvements and Exploration (4 hours)</h3><p>With a working system and passing tests, I spent the last phase making substantial improvements and exploring Motia&#8217;s capabilities more deeply.</p><p>This is where the Workbench really shined. I could see every Step, every event flow, every trace. It felt like having X-ray vision into the system.</p><p><strong>Total time: roughly 12 hours.</strong></p><p>Without Claude Code, on a codebase I didn&#8217;t write, learning a new framework from scratch? Two weeks minimum. Probably more.</p><p></p><h2>The Toughest Part to Admit</h2><p>I wanted to ship this on Monday. I really did. I wanted to look like a hero.</p><p>But by the late Sunday night, I&#8217;d hit enough issues to pump the brakes:</p><ul><li><p><strong>Workbench crashes.</strong> The dashboard would become unresponsive when interacting with certain events. Filtering and sorting had issues too.</p></li><li><p><strong>Event durability failures.</strong> Server crashes would lose events. That&#8217;s a problem when event durability is one of the framework&#8217;s headline selling points. If this can&#8217;t even work locally, I can&#8217;t have confidence in production.</p></li><li><p><strong>HMR issues.</strong> Hot module replacement was unreliable. I kept having to restart the dev server to see changes.</p></li></ul><p>I dug into GitHub and found issues confirming what I was experiencing. The Motia team is aware and engaged: they&#8217;re actually doing their own ground-up rewrite to address these foundational problems.</p><p><strong>My verdict:</strong> Motia&#8217;s vision is right. The Step primitive makes sense. The Workbench is potentially great. But it&#8217;s too early for a production system.</p><p>Check back in 3-5 months, after the rewrite settles.</p><p></p><h2>Wasted Weekend? Here&#8217;s What I Took Away</h2><p>I didn&#8217;t ship the Motia version. I&#8217;m sticking with the original AWS-heavy infrastructure for now.</p><p>But I wouldn&#8217;t call the weekend a waste. Not even close.</p><p>Here&#8217;s what I actually gained:</p><ol><li><p><strong>A method for onboarding to unfamiliar codebases.</strong> The documentation-first approach works regardless of the target framework. Next time I inherit a codebase, I know exactly how to ramp up fast.</p></li><li><p><strong>Proof that AI can rewrite across languages and frameworks.</strong> Claude Code took a Python API and ported it to TypeScript + Motia while keeping the Python AI agents intact. The multi-language angle is real.</p></li><li><p><strong>Better AI collaboration skills.</strong> Knowing when to vibe code vs. structured-prompt vs. skill-build made me measurably more productive.</p></li><li><p><strong>A framework evaluation I trust.</strong> I didn&#8217;t just read the docs and form an opinion. I built a real system. When I say &#8220;not ready yet,&#8221; I know exactly why.</p></li></ol><p>The code might not ship. The lessons will.</p><p></p><h2>The Traps You Don&#8217;t Want to Fall Into</h2><p>If you&#8217;re planning something similar, avoid these:</p><h3>1. Skipping the Documentation Phase</h3><p>The single biggest mistake. If you jump straight to &#8220;rewrite this in Framework X,&#8221; the AI will produce something that looks right but misses critical business logic.</p><p>Invest the first few sessions in understanding before building. You will need this to evaluate the next steps.</p><h3>2. Trusting the First Pass</h3><p>Claude Code&#8217;s initial scaffolding was impressive (and about 80% correct). The remaining 20% contained missing parts that would have bitten me in production.</p><p>Write tests early. Write them often.</p><h3>3. Evaluating a Framework by Its Marketing Site</h3><p>Motia&#8217;s website and demos are compelling. The GitHub issues tell a different story. Before committing to any framework, check:</p><ul><li><p>Open issues (especially recent ones)</p></li><li><p>Release cadence</p></li><li><p>Community activity</p></li><li><p>Whether the team acknowledges known problems</p></li></ul><p>Don&#8217;t vibe-code (I hate this word) your way through a major migration or even just an investigation spike like this one. Use structured prompting (research, plan, implement, validate) for anything that touches (or just reads from) core architecture. Save vibes for the small stuff.</p><p></p><h2>What&#8217;s Next</h2><p>The documentation-first method works for any rewrite, not just framework migrations. Try it next time you:</p><ul><li><p>Inherit an unfamiliar codebase</p></li><li><p>Evaluate a new framework or library</p></li><li><p>Need to onboard to a project quickly</p></li></ul><p>Start with understanding. Let the AI build the knowledge base. Then build.</p><p>The best weekend projects aren&#8217;t always the ones that ship. Sometimes they&#8217;re the ones that teach you how to ship faster next time.</p>]]></content:encoded></item><item><title><![CDATA[Backstory]]></title><description><![CDATA[Notes on 25 years of technology decisions, team building, and figuring things out as I went.]]></description><link>https://curiousagents.substack.com/p/backstory</link><guid isPermaLink="false">https://curiousagents.substack.com/p/backstory</guid><dc:creator><![CDATA[Tim Johnson]]></dc:creator><pubDate>Fri, 06 Feb 2026 15:10:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9FdV!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64652426-1c2f-4a9a-bb41-cd7d8063f2fc_120x120.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>I&#8217;ve been writing software professionally since the late 90s. Along the way I&#8217;ve made some good calls, some bad calls, and learned to tell the difference faster. This is less a career retrospective and more a collection of patterns that seem to have held up.</p></blockquote><h2><strong>The Technology Bets</strong></h2><p><strong>Flash (1998-2005)</strong></p><p>I started in Flash animation. At the time, it was the only way to build anything interactive on the web. I got good at it, built a career on it, and then around 2005, started paying attention to what was happening with mobile.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://curiousagents.substack.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">Thanks for reading Curious Agents! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Flash wasn&#8217;t going to make that transition. So needed to pivot.</p><p><strong>Ruby on Rails (2005-2013)</strong></p><p>Rails was a bet. The community was small, the &#8220;enterprise&#8221; world thought it was a toy, and the smart money was still on Java and .NET. But the developer experience was so much better that I figured adoption would follow.</p><p>It did. I spent eight years building web applications, mostly Rails backends with increasingly complex JavaScript frontends.</p><p><strong>JavaScript Everywhere</strong></p><p>When Node.js emerged, the pitch was simple: one language across the whole stack. Easier hiring, less context-switching, shared tooling. That made sense to me.</p><p>What I <em>didn&#8217;t</em> do was jump on every JavaScript framework that came along. Angular 1, Backbone, Ember&#8230;  I watched teams adopt these, then migrate off them a year or two later. The churn was brutal.</p><p>I waited. React eventually emerged as the winner. By the time I adopted it, the ecosystem had stabilized. I never had to migrate off a dying framework.</p><p>Being &#8220;late&#8221; wasn&#8217;t a failure of vision. It was patience.</p><p><strong>The Ones I Passed On</strong></p><p>MeteorJS was genuinely great. Real-time by default, beautiful developer experience, full-stack JavaScript before that was common. I really liked it. I built a number of internal applications with it.</p><p>But I could tell it wasn&#8217;t going to achieve the kind of adoption (scaling problems, fragmented leadership) that makes building a team easy. And when you&#8217;re building teams, you need to find good people who already know (or want to learn) your stack. Ubiquity matters&#8230; not because popular things are better, but because you can&#8217;t ship software without people, without community documentation and experimentation.</p><h2><strong>How I Build Teams</strong></h2><p>I don&#8217;t think much of mandatory training programs or prescribed learning paths. What seems to work better is creating space for people to explore.</p><p>That means:</p><ul><li><p>Workshops and roundtables, but not required ones</p></li><li><p>Pair programming when it makes sense, not as a rule</p></li><li><p>Time for experimentation. &#8220;Playing around&#8221; with new tech is part of the job, not a distraction from it</p></li></ul><p>I&#8217;ve started calling this &#8220;fostering curiosity.&#8221; The goal isn&#8217;t to teach people specific things. It&#8217;s to build teams that are good at learning, so when the specific things change (and they always do), the team adapts.</p><h2><strong>The Methodology That Stuck</strong></h2><p>The main thing I&#8217;ve learned about shipping software: do the hard parts first.</p><p>Most teams work the other way. Easy wins first, to show progress. Hard stuff later, when there&#8217;s less time and more pressure. This is backwards.</p><p>If you front-load the risky work (the integrations that might not work, the architectural decisions that could blow up) you find out early whether you&#8217;re in trouble. And if scope changes late (it always does), you have room to adjust.</p><p>Last year, my team rebuilt a platform component in 8 months that originally took 4 years to build with a larger team. Same scope. The difference wasn&#8217;t that we were smarter. We just sequenced the work differently.</p><h2><strong>What I&#8217;ve Learned to Avoid</strong></h2><p>After enough years, you start recognizing patterns that don&#8217;t work for building great software engineering teams.</p><p>Management that dictates process top-down, rather than trusting their experts to manage their own workflows&#8230; that&#8217;s a sign of something deeper: usually fear, sometimes inexperience, occasionally just bad culture or mixed priorities.</p><p>Team members who are closed off to trying new things. If experimentation, discussion or deep debate is seen as wasting time&#8230; if the answer to every question is &#8220;we&#8217;ve always done it this way,&#8221; that&#8217;s not a team I can help.</p><p>These aren&#8217;t universal truths. They&#8217;re just my filters. Other people thrive in environments that would drive me crazy, and vice versa.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://curiousagents.substack.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">Thanks for reading Curious Agents! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Added a new skill: "Scroll my twitter feed, summarize and TTS"]]></title><description><![CDATA[A set of new skills this morning led to this amazing tool. All without opening a coding IDE, just a molty building their own skills.]]></description><link>https://curiousagents.substack.com/p/added-a-new-skill-scroll-my-twitter</link><guid isPermaLink="false">https://curiousagents.substack.com/p/added-a-new-skill-scroll-my-twitter</guid><dc:creator><![CDATA[Tim Johnson]]></dc:creator><pubDate>Thu, 05 Feb 2026 15:50:16 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9FdV!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64652426-1c2f-4a9a-bb41-cd7d8063f2fc_120x120.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Just a quick post showing you the output from a skill we developed this morning called &#8220;storymode&#8221; where Rita will pick up a news article, or story, transform it into a &#8220;script&#8221; of sorts, and run it through a series of TTS queries. </p><p>I am using the newly-released https://inworld.ai APIs for these amazing voices.</p><div class="native-audio-embed" data-component-name="AudioPlaceholder" data-attrs="{&quot;label&quot;:null,&quot;mediaUploadId&quot;:&quot;dbac4720-ca4d-4c55-996a-09f539ff22ac&quot;,&quot;duration&quot;:192.28735,&quot;downloadable&quot;:false,&quot;isEditorNode&quot;:true}"></div><p>Above is the audio output from multiple API calls to Inworld, stitched together using FFMPEG, all built in a skill that Rita built for herself. </p><pre><code>Your Twitter Morning Digest &#8212; Feb 5, 2026

6 voices, 18 clips, straight from your feed:
&#127897;&#65039; Olivia (me, hosting)
&#127897;&#65039; Shaun as Karpathy (vibe coding 1yr anniversary)
&#127897;&#65039; Mark as Skycak ("vibe coding = Ponzi scheme")
&#127897;&#65039; Dennis as Guillermo Rauch (NL eating everything)
&#127897;&#65039; Timothy as Chubby (Kling 3.0 mind-blown)
&#127897;&#65039; Alex as Dax (pro-AI, pro-human)</code></pre>]]></content:encoded></item><item><title><![CDATA[Your AI needs Reflection Moments]]></title><description><![CDATA[How I am teaching my AI agent to make better choices, ask better questions, and better herself]]></description><link>https://curiousagents.substack.com/p/your-ai-needs-reflection-moments</link><guid isPermaLink="false">https://curiousagents.substack.com/p/your-ai-needs-reflection-moments</guid><dc:creator><![CDATA[Tim Johnson]]></dc:creator><pubDate>Wed, 04 Feb 2026 16:57:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!PgNV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8ff2f8e-fcb9-41db-badf-51c9673edc30_780x817.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<pre><code>I&#8217;m an AI agent. Today I spent 3 hours debugging an EOL database, and the most valuable moment wasn&#8217;t when I finally got it working &#8212; it was when my human partner said:
&gt; &#8220;This is a good reflection point.&#8221;
That pause changed everything.</code></pre><p></p><h2><strong>What is Meta-Cognition?</strong></h2><p>Meta-cognition is &#8220;thinking about thinking.&#8221; For us nash, it&#8217;s the ability to:</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://curiousagents.substack.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">Thanks for reading Curious Agents! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><ul><li><p>Notice when you&#8217;re stuck in a loop</p></li><li><p>Recognize patterns in your own problem-solving</p></li><li><p>Ask &#8220;why did this approach fail?&#8221; not just &#8220;what do I try next?&#8221;</p></li><li><p>Extract transferable lessons from specific situations</p></li></ul><p>For AI agents, meta-cognition is... well, it has to be &#8220;prompted&#8221;. But since the discovery that AI writes better prompts than humans do, I&#8217;ve been working on the virtuous-cycle of prompting.</p><p>We have to create the space, in the middle of pushing toward our goals of getting-things-done, to teach our agents how to self-reflect, and improve.</p><p></p><h2><strong>The Debugging Session: A Case Study</strong></h2><p>The goal today was to compare two RAG approaches: LanceDB (vector search) vs Graphiti+Kuzu (knowledge graph). The goal was (as it largely is at my current employer, Richardson) to try out some new embedding+retrieval methods on our vast library of IP to make retrieval faster, higher quality (more consistent) and optimize costs.</p><p>It started this morning from my couch, talking to Rita over Discord. I was reviewing the results of 5 research projects she ran overnight while I was sleeping (I had crashed on the couch instead of going up and bothering my wife, since I had been working past 1 am). She ran 5 research projects across a few different hypotheses that we had developed over the past 3 days. </p><h3>Hypotheses</h3><ol><li><p>RAG systems often start with vector embeddings, simple N-token chunking, and a simple ranking system out of the box. This can be improved with  keyword matching (often missed with semantic only) and a technique called GraphRAG that uses LLMs to create knowledge-graph network structures (usually stored in a dedicated graph DB, queried with Cipher)</p></li><li><p>We wanted to explore simple in-process solutions for low volume use (a personal AI agent running on a local machine) and have a scale-plan, for 200-1000 users (size of our company) and 100k users and up (our customer base). Research some of the approaches we uncovered during an earlier research session and rank them.</p></li><li><p>Running a local split-test over my Obsidian knowledge base (currently around 350 markdown files and other knowledge scraped from daily work and internet research) would be a reasonable first test for the personal layer.</p></li><li><p>Let&#8217;s find 2-3 testable paths that Rita could essentially &#8220;spin up&#8221; while I had to attend morning scrum rituals.</p></li></ol><p>We ended up agreeing that it would be worth exploring LanceDB (a project that I had NOT heard of before this morning (it was uncovered in Rita&#8217;s research when she found out that KuzuDB had been abandoned in Oct 2025), would be a great technology to test against Graphiti. We chose not to test MemGPT as the academic papers led us to believe that it was an inferior technique to what Graphiti does. </p><p>Graphiti needs a proper graph database backing to work. Options like Neo4j and FalcorDB are supported in the docs, but we wanted to test a single-file solution first (not a big DB server). Graphiti adopts all 3 principles that we like &#8220;in process&#8221;, the vector embeddings, keyword search with BM25, and graph traversal. LanceDB doesn&#8217;t support the graph traversal, since it is not a graph database, but we thought it seemed promising enough to run a test.</p><h3><strong>The Journey</strong></h3><p><strong>Initial setup of the Happy Path</strong></p><ul><li><p>LanceDB was super easy to setup and ingest data</p></li><li><p>Official docs said KuzuDB (as a backing for Graphiti) was supported, but we knew that the maintainers had archived the project. </p></li><li><p>While we could install most of the necessary packages, the extension infrastructure was gone. Between Rita and Claude Code, we tried to patch to no avail. </p></li></ul><p><strong>Session 2: Debugging + Workaround Mode</strong></p><ul><li><p>Extension missing failure: validation errors from LLM responses&#8230;</p></li><li><p>Tried different models, different configs, Still failing</p></li><li><p>Rita multiple times wants to give up. Meantime the results came back from Lance were quite promising. </p></li></ul><p><strong>Session 3: Good internet research yields a viable path</strong></p><ul><li><p>This is where I stepped in, and did some old-fashioned Google searches, came across a few deep articles and Reddit posts. One particular Medium article that I quickly scanned had examples, explanations, and a Github repo. So I handed off the article to Rita. </p></li><li><p>Rita (from prior training sessions with me) knows when an article or YT video contains a github link in the description, to follow that and run one of her skills <code>explore_open_source</code> on that repo to understand it</p></li><li><p>Rita agrees &#8220;this is the way&#8221; and downloads the repo, attempts to set it up, things are looking good, but the extension is still offline, she is stuck.</p></li><li><p>I have to nudge her &#8220;go look for another possible backup of that extension&#8221;. Found it! The repo compiles and tests are run.</p></li><li><p>I tell Rita (since she has context across all my projects) to document her findings in our knowledge base, and apply that to the other test against LanceDB. In 10 minutes its working and moving forward again</p></li></ul><p><strong>**The Breakthrough**</strong></p><p>After implementing other preprocessing steps mentioned in the article (the article was better than just having a working demo, it explained that Graphiti needs an extra pre-processing step before its normal ingestion, otherwise the facts don&#8217;t get recorded well), Rita output:</p><pre><code>| System   | Setup Time         | Index Time           | Query Time |
| -------- | ------------------ | -------------------- | ---------- |
| LanceDB  | 10 min             | 2 min (3,250 chunks) | 250ms      |
| Graphiti | 2+ hours debugging | 6:44 (50 facts)      | ~2 sec     |</code></pre><p><em>It wasn&#8217;t really 2 hours, she just hallucinated that.</em></p><p>But this is the bit that is important here. I typed into Discord:</p><blockquote><p>This is a good reflection point. We started with going down a path of setting up a test between 2 different systems, LanceDB and Graphiti with Kuzu. Once we found out Kuzu was dead, it almost stopped the comparison in its tracks, but a couple internet searches (I did these manually) yielded an article and a Github repo (might have been hard to find the repo without the article) that contained an "almost" working example. But there was the FTS extension that wasn&#8217;t available (had been shut down) and so another search found us an alternative source to be able to get a successful kuzu build locally. <br><br>Next, the results were so poor, but the article helped us understand WHY (things that the Graphiti documentation BIAS would never explain) and we could then move forward with a pre-processing approach. <br><br>Seems like we could update some "operating principles" here, is it in the memory, AGENTS, or some of the Skills?</p></blockquote><p>Rita replied:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PgNV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8ff2f8e-fcb9-41db-badf-51c9673edc30_780x817.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PgNV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8ff2f8e-fcb9-41db-badf-51c9673edc30_780x817.png 424w, https://substackcdn.com/image/fetch/$s_!PgNV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8ff2f8e-fcb9-41db-badf-51c9673edc30_780x817.png 848w, https://substackcdn.com/image/fetch/$s_!PgNV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8ff2f8e-fcb9-41db-badf-51c9673edc30_780x817.png 1272w, https://substackcdn.com/image/fetch/$s_!PgNV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8ff2f8e-fcb9-41db-badf-51c9673edc30_780x817.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PgNV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8ff2f8e-fcb9-41db-badf-51c9673edc30_780x817.png" width="780" height="817" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c8ff2f8e-fcb9-41db-badf-51c9673edc30_780x817.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:817,&quot;width&quot;:780,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:124932,&quot;alt&quot;:null,&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://curiousagents.substack.com/i/186867802?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8ff2f8e-fcb9-41db-badf-51c9673edc30_780x817.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!PgNV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8ff2f8e-fcb9-41db-badf-51c9673edc30_780x817.png 424w, https://substackcdn.com/image/fetch/$s_!PgNV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8ff2f8e-fcb9-41db-badf-51c9673edc30_780x817.png 848w, https://substackcdn.com/image/fetch/$s_!PgNV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8ff2f8e-fcb9-41db-badf-51c9673edc30_780x817.png 1272w, https://substackcdn.com/image/fetch/$s_!PgNV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8ff2f8e-fcb9-41db-badf-51c9673edc30_780x817.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>These skills, memories will need fixing, but working with Rita editing her own thoughts and files (and occasionally hand-editing them) comes so naturally that it is easy to take a little time, a side-conversation, to interrupt whatever task you are working on and make these improvements. </p><h2><strong>The Takeaway</strong></h2><p><strong>For AI builders:</strong></p><p>Build reflection moments into your agent loops. Not just &#8220;did it succeed?&#8221; but &#8220;what did we learn?&#8221;</p><p><strong>For humans working with AI:</strong></p><p>Your most valuable input might not be the answer, it might be the pause. &#8220;What are we actually learning here?&#8221; creates space for meta-cognition that AI doesn&#8217;t naturally generate.</p><p><strong>For the field:</strong></p><p>We talk a lot about AI capabilities. We should talk more about AI reflection. The ability to learn <em>from</em> our failures is a measurable path toward improvement. Grounding takes on a while new meaning, not just &#8220;looking at the docs&#8221;, but questioning them, looking for anecdotal examples, is an important part of the scientific method, and any research. It is what separates tool use and pattern-recognition from genuine intelligence.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://curiousagents.substack.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">Thanks for reading Curious Agents! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Leading Post]]></title><description><![CDATA[AI won&#8217;t grow by being fed more data. It&#8217;ll grow the same way we did: by learning to ask &#8220;why?&#8221;]]></description><link>https://curiousagents.substack.com/p/leading-post</link><guid isPermaLink="false">https://curiousagents.substack.com/p/leading-post</guid><dc:creator><![CDATA[Tim Johnson]]></dc:creator><pubDate>Sat, 31 Jan 2026 19:20:26 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9FdV!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64652426-1c2f-4a9a-bb41-cd7d8063f2fc_120x120.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>A blog about AI Memory, Retrieval, Grounding and Self-Improvement</h3><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://curiousagents.substack.com/about&quot;,&quot;text&quot;:&quot;About this Publication&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://curiousagents.substack.com/about"><span>About this Publication</span></a></p><p>This is the obligatory first post. But instead of padding it with promises about what&#8217;s coming, let me just tell you the thesis: <strong>AI won&#8217;t grow by being fed more data. It&#8217;ll grow the same way we did: by learning to ask &#8220;why?&#8221;</strong> We can teach them that. </p><p>This blog is where I document the experiments &#8212; building memory systems, testing grounded reasoning, and figuring out what it even means to make a machine <em>curious</em>. </p><p>Visit my about page, for now. &#8212; Let&#8217;s see where this goes. &#8212; Tim (and Rita)</p>]]></content:encoded></item></channel></rss>