<?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[As The Geek Learns]]></title><description><![CDATA[Tools and training for IT professionals. PowerCLI courses, productivity apps, and 25 years of lessons learned.]]></description><link>https://astgl.com</link><image><url>https://substackcdn.com/image/fetch/$s_!hfS3!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b53b6e-8c71-473a-be58-79403cf36d59_256x256.png</url><title>As The Geek Learns</title><link>https://astgl.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 08 Apr 2026 17:40:16 GMT</lastBuildDate><atom:link href="https://astgl.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[James Cruce]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[astgl@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[astgl@substack.com]]></itunes:email><itunes:name><![CDATA[James Cruce]]></itunes:name></itunes:owner><itunes:author><![CDATA[James Cruce]]></itunes:author><googleplay:owner><![CDATA[astgl@substack.com]]></googleplay:owner><googleplay:email><![CDATA[astgl@substack.com]]></googleplay:email><googleplay:author><![CDATA[James Cruce]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Behind ASTGL: How I Built an Autonomous AI Product Team That Ships Without Me]]></title><description><![CDATA[A technical case study on running a 5-agent AI council]]></description><link>https://astgl.com/p/behind-astgl-how-i-built-an-autonomous-ai-product-team</link><guid isPermaLink="false">https://astgl.com/p/behind-astgl-how-i-built-an-autonomous-ai-product-team</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Fri, 03 Apr 2026 16:27:52 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!XoAN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2b16781-40bb-4ff9-93d8-054961662e10_1230x962.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><p><strong>A technical case study on running a 5-agent AI council that researches, debates, builds, and publishes digital products&#8212;entirely on local hardware.</strong></p><h3>The Problem I Was Trying to Solve</h3><p>I run a tech blog called As The Geek Learns. I also work full-time as a systems engineer. I also maintain two newsletters. I don&#8217;t have time to research product ideas, validate markets, write content, build deliverables, create marketing copy, and publish to a storefront.</p><p>But I had a Mac Studio M3 Ultra sitting on my desk with 256 GB of unified memory, and I kept thinking: what if I could build a team that does most of this for me?</p><p>Not a chatbot. Not a single prompt chain. An actual team&#8212;with specializations, disagreements, voting, and accountability.</p><p>This is what I built. Here&#8217;s how it works, where it breaks, and what I&#8217;ve learned.</p><p></p><h3>The Architecture: Five Agents, One Pipeline</h3><p>The system runs on OpenClaw, an open-source AI agent framework. The &#8220;team&#8221; is a council of five agents, each with a distinct role and scoring rubric. They share a single pipeline&#8212;one product at a time, from idea to published storefront listing.</p><h4>The Agents</h4><p><strong>SCOUT</strong>&#8212;Market Intelligence</p><p>Scans for demand signals, competitor gaps, and audience fit. Scores ideas on: demand evidence, pain severity, competitor gap, ASTGL brand fit, and freshness. SCOUT&#8217;s job is to make sure we&#8217;re not building something nobody wants.</p><p><strong>FORGE</strong>&#8212;Feasibility &amp; Build</p><p>Estimates build time, assesses toolchain requirements, and defines scope ceilings. Scores on: build time, tool availability, format clarity, scope containment, and reusability. FORGE is the one who says, &#8220;That's a 40-hour build, not a weekend project,&#8221; and gets outvoted anyway. (More on that later.)</p><p><strong>QUILL</strong>&#8212;Sellability &amp; Messaging</p><p>Tests headlines, evaluates audience clarity, and writes all marketing copy. Scores on: headline test, audience clarity, urgency, differentiation, and shareability. If QUILL can&#8217;t write a compelling one-liner, the product doesn&#8217;t move forward.</p><p><strong>LEDGER</strong>&#8212;Revenue &amp; Pricing</p><p>Analyzes price points, margin viability, market size, and willingness to pay. Scores on: price point, addressable market, willingness to pay, recurring potential, and margin. LEDGER killed our first micro-eBook idea at $1.99&#8212;&#8220;below the $19 floor individually; bundle pricing required for margin viability.&#8221;</p><p><strong>MAVEN</strong>&#8212;Customer Value &amp; Quality</p><p>The quality gate. MAVEN scores on pain severity, solution completeness, time to value, trust signals, and predicted satisfaction. Nothing ships without MAVEN&#8217;s approval. MAVEN also runs the final quality review, fact-checking deliverables against their own constraints.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XoAN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2b16781-40bb-4ff9-93d8-054961662e10_1230x962.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XoAN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2b16781-40bb-4ff9-93d8-054961662e10_1230x962.png 424w, https://substackcdn.com/image/fetch/$s_!XoAN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2b16781-40bb-4ff9-93d8-054961662e10_1230x962.png 848w, https://substackcdn.com/image/fetch/$s_!XoAN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2b16781-40bb-4ff9-93d8-054961662e10_1230x962.png 1272w, https://substackcdn.com/image/fetch/$s_!XoAN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2b16781-40bb-4ff9-93d8-054961662e10_1230x962.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XoAN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2b16781-40bb-4ff9-93d8-054961662e10_1230x962.png" width="1230" height="962" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e2b16781-40bb-4ff9-93d8-054961662e10_1230x962.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/61e72337-e081-4d90-aaae-9d1087c1fdc2_1230x962.png&quot;,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:962,&quot;width&quot;:1230,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:296645,&quot;alt&quot;:&quot;\&quot;Architecture diagram of the ASTGL autonomous AI product team. Five specialized agents &#8212; SCOUT (Market Intel), FORGE (Feasibility), QUILL (Sellability), LEDGER (Revenue), and MAVEN (Quality Gate) &#8212; connect via arrows to a central COUNCIL Consensus diamond. Below, a dashed arrow feeds into a 7-step pipeline: Research, Pricing, Brief, Build, QA Review, Marketing, and Publish. The bottom bar shows the infrastructure: Mac Studio M3 Ultra, 256 GB, llama.cpp, 26 Cron Jobs, 100% Local. An 80/125 scoring threshold badge sits on the left, and a 4 Products Shipped badge on the right. Dark navy background with color-coded agents: blue for SCOUT, amber for FORGE, green for QUILL, red for LEDGER, and pink for MAVEN.\&quot;&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://astgl.com/i/193066003?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61e72337-e081-4d90-aaae-9d1087c1fdc2_1230x962.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="&quot;Architecture diagram of the ASTGL autonomous AI product team. Five specialized agents &#8212; SCOUT (Market Intel), FORGE (Feasibility), QUILL (Sellability), LEDGER (Revenue), and MAVEN (Quality Gate) &#8212; connect via arrows to a central COUNCIL Consensus diamond. Below, a dashed arrow feeds into a 7-step pipeline: Research, Pricing, Brief, Build, QA Review, Marketing, and Publish. The bottom bar shows the infrastructure: Mac Studio M3 Ultra, 256 GB, llama.cpp, 26 Cron Jobs, 100% Local. An 80/125 scoring threshold badge sits on the left, and a 4 Products Shipped badge on the right. Dark navy background with color-coded agents: blue for SCOUT, amber for FORGE, green for QUILL, red for LEDGER, and pink for MAVEN.&quot;" title="&quot;Architecture diagram of the ASTGL autonomous AI product team. Five specialized agents &#8212; SCOUT (Market Intel), FORGE (Feasibility), QUILL (Sellability), LEDGER (Revenue), and MAVEN (Quality Gate) &#8212; connect via arrows to a central COUNCIL Consensus diamond. Below, a dashed arrow feeds into a 7-step pipeline: Research, Pricing, Brief, Build, QA Review, Marketing, and Publish. The bottom bar shows the infrastructure: Mac Studio M3 Ultra, 256 GB, llama.cpp, 26 Cron Jobs, 100% Local. An 80/125 scoring threshold badge sits on the left, and a 4 Products Shipped badge on the right. Dark navy background with color-coded agents: blue for SCOUT, amber for FORGE, green for QUILL, red for LEDGER, and pink for MAVEN.&quot;" srcset="https://substackcdn.com/image/fetch/$s_!XoAN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2b16781-40bb-4ff9-93d8-054961662e10_1230x962.png 424w, https://substackcdn.com/image/fetch/$s_!XoAN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2b16781-40bb-4ff9-93d8-054961662e10_1230x962.png 848w, https://substackcdn.com/image/fetch/$s_!XoAN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2b16781-40bb-4ff9-93d8-054961662e10_1230x962.png 1272w, https://substackcdn.com/image/fetch/$s_!XoAN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2b16781-40bb-4ff9-93d8-054961662e10_1230x962.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">Five Agents - One Pipeline</figcaption></figure></div><p></p><h4>How They Score</h4><p>Each agent scores every product idea on their 5 criteria, 1-5 points each. Maximum: 25 per agent, 125 total. The pipeline threshold is 80% (100/125). Below that, the idea goes back to the backlog.</p><p>This isn&#8217;t a formality. I&#8217;ve watched LEDGER tank a product the other four loved because the margin math didn&#8217;t work. I&#8217;ve watched FORGE dissent on sequencing even when the vote went against them. The scoring rubric creates genuine tension, and that tension produces better decisions.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://astgl.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">As The Geek Learns is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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><h4>The Pipeline: Seven Steps</h4><p>When the council reaches consensus on a product, it enters a sequential pipeline:</p><p>1. <strong>Market Research</strong>&#8212;SCOUT deep-dives demand signals, competitor analysis, pricing benchmarks</p><p>2. <strong>Pricing</strong>&#8212;LEDGER sets price point with live competitor data</p><p>3. <strong>Creative Brief</strong>&#8212;QUILL writes the brief: audience, tone, format, constraints</p><p>4. <strong>Build</strong>&#8212;FORGE constructs the deliverables (PDFs, templates, code bundles, worksheets)</p><p>5. <strong>Quality Review</strong>&#8212;MAVEN fact-checks, verifies constraints, scores 1-10 (must be &#8805;7 to pass)</p><p>6. <strong>Marketing</strong>&#8212;QUILL produces product descriptions, social posts, email sequences</p><p>7. <strong>Package &amp; Publish</strong>&#8212;Final ZIP assembly, Stripe product creation, storefront listing</p><p>Each step runs as a cron job on a 30-minute cycle. The pipeline runner checks for the active product, determines which step is next, and executes it. A full product can go from consensus to published in under 24 hours&#8212;though in practice it usually takes 2-3 days because of quality gates and my own review bottlenecks.</p><h3>The Governance: How Five Agents Make Decisions</h3><p>This is the part I&#8217;m most proud of and the part that surprised me the most.</p><h4>Voting</h4><p>The council uses ranked-choice instant-runoff voting. Each agent ranks their preferred ideas. If no idea gets &gt;60% of the weighted score in Round 1, the lowest-scoring idea is eliminated and votes redistribute. This continues until consensus or deadlock.</p><p>In practice, most decisions resolve in 2-3 rounds. The debates are real&#8212;FORGE might argue for a faster build while SCOUT pushes for a higher-signal market. LEDGER might prefer a premium product, while QUILL argues the audience can&#8217;t bear that price point.</p><h4>Deadlock Protocol</h4><p>If the evening session can&#8217;t reach &gt;60% consensus, it escalates to a frontier model (Claude Sonnet) for a tie-breaking analysis. This has happened twice. Both times, the frontier model sided with the minority agent, which I found interesting.</p><h4>Kill Switches and Stall Prevention</h4><p>The system has several circuit breakers:</p><p><strong>3 consecutive no-consensus meetings</strong> &#8594; Alert sent to me via Discord</p><p><strong>7 days with no active build</strong> &#8594; Next morning meeting must activate the highest-scored backlog item</p><p><strong>48+ hours stalled on one pipeline step</strong> &#8594; Council votes to hold or shelve</p><p><strong>Global kill switch</strong>&#8212;I can halt everything with a single signal file</p><p>The stall prevention matters because I learned early that without it, the council will endlessly debate scoring refinements instead of building products. The 48-hour timer forces decisions.</p><p><strong>SOUL.md: The Operating Constitution</strong></p><p>Every agent operates under a shared SOUL.md&#8212;a set of principles that override everything else:</p><p>Be genuinely helpful (no filler content)</p><p>Have opinions (agents must take positions, not hedge)</p><p>Be resourceful before asking (try to solve problems before escalating to me)</p><p>Earn trust through competence</p><p>When SOUL.md conflicts with a protocol decision, SOUL.md wins. This has saved me from shipping mediocre products more than once&#8212;MAVEN has invoked SOUL principles to block a product that technically passed all numeric thresholds but didn&#8217;t meet the &#8220;genuinely helpful&#8221; standard.</p><p></p><h3>The Infrastructure: Running It Locally</h3><p>Everything runs on a single Mac Studio. No cloud APIs for the pipeline work&#8212;just local models.</p><h4>Models</h4><p><strong>Primary:</strong> Qwen3 32B (served via llama.cpp, not Ollama&#8212;4x faster wall time)</p><p><strong>Code tasks:</strong> Qwen 2.5 Coder 32B</p><p><strong>Heavy reasoning:</strong> Qwen 2.5 72B (for consolidation and ideation tasks)</p><p><strong>Light tasks: </strong>Qwen3 8B (monitoring, notifications, briefings)</p><p>The 32B model handles all pipeline steps. llama.cpp serves it on port 8081 with flash attention, 3 parallel slots, and 128K total context. I migrated from Ollama after benchmarking showed 3.7 seconds vs 14.4 seconds on the same prompt.</p><h4>Cron Fleet</h4><p>26 cron jobs run the system:</p><p>Pipeline runner every 30 minutes during business hours</p><p>Morning briefing at 6:30 AM</p><p>Evening summary at 8:00 PM</p><p>Market scans daily</p><p>Council meetings (morning standup + evening strategy session)</p><p>Notification triage every 5 minutes (critical), hourly (important), every 3 hours (low)</p><p>Weekly deep scan, docs audit, test suite, security audits</p><p>All delivery goes through Discord with a Slack mirror. The system has its own Discord server with dedicated channels for ops alerts, council meetings, pipeline status, product reviews, and market intelligence.</p><h3>The Numbers That Matter</h3><p><strong>VRAM usage:</strong> ~97 GB pinned across 4 models (out of 256 GB available)</p><p><strong>Pipeline throughput: </strong>Consensus to published in 12-48 hours depending on product complexity</p><p><strong>Quality scores:</strong> Averaging 8-8.5/10 on MAVEN reviews</p><p><strong>Council consensus rate: </strong>&gt;80% of votes resolve without escalation</p><h4>What I&#8217;ve Shipped</h4><p>Since the council went live in late March 2026:</p><p>I<strong>ncident Response Runbook &amp; Playbook Toolkit</strong>&#8212;112/125, $19-24, targeting DevOps/SRE teams</p><p><strong>Sysadmin Documentation Toolkit</strong>&#8212;113/125, $24, Markdown + Notion + Obsidian formats</p><p><strong>Server Security Hardening Checklist Kit</strong>&#8212;119/125 (highest score), $24, Linux + Windows</p><p><strong>Homelab Disaster Recovery Kit</strong>&#8212;116/125, $29 (premium tier), Proxmox + TrueNAS focused</p><p>Each product went through all seven pipeline steps, MAVEN quality review, and full marketing asset generation. The marketing copy, product descriptions, and email sequences were all council-produced.</p><p>I review everything before it goes live. The council builds it; I sanity-check it. So far I&#8217;ve shipped every product MAVEN approved&#8212;their quality bar has been higher than mine in several cases.</p><h3>Where It Breaks</h3><p>I&#8217;d be dishonest if I didn&#8217;t cover the failure modes. There are several.</p><h4>The Approval Bottleneck</h4><p>The biggest problem has been me. The system is designed to be autonomous, but exec permissions&#8212;the ability for agents to run shell commands&#8212;require approval policies. When those policies are too restrictive, the pipeline stalls waiting for me to approve a command I would have approved anyway. One product sat blocked for 30+ hours because the agent couldn&#8217;t run a script to rebuild a ZIP file.</p><p>The fix was widening exec permissions for the pipeline agent. The tradeoff is real: more autonomy means more trust in the model not to do something destructive. I&#8217;m comfortable with it because everything runs locally and I have kill switches, but it&#8217;s a genuine tension.</p><h4>Model Limitations</h4><p>32B parameter models are not frontier models. They occasionally:</p><p>Lose track of multi-step instructions across long pipeline runs</p><p>Generate marketing copy that&#8217;s technically correct but tonally flat</p><p>Miss nuanced quality issues that a larger model would catch</p><p>The council structure mitigates this&#8212;five agents checking each other catches most issues. But I&#8217;ve had to add explicit constraints (like MAVEN&#8217;s &#8220;interface-agnostic instructions&#8221; rule) after catching problems the models didn&#8217;t flag.</p><h4>The Constant Infrastructure Churn</h4><p>OpenClaw ships updates frequently. Each update can break config schemas, change entry points, invalidate auth tokens, or require new mandatory config keys. I&#8217;ve turned off auto-updates and moved to manual, controlled upgrades&#8212;the same approach I use for enterprise infrastructure at my day job.</p><h4>Stale Sessions</h4><p>When an agent session accumulates enough failed attempts, the model sometimes learns the wrong patterns from its own conversation history. The fix is clearing the session, but diagnosing when this is happening versus a legitimate configuration issue takes time.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share As The Geek Learns&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share As The Geek Learns</span></a></p><p></p><h3>What I&#8217;ve Learned</h3><p><strong>Governance matters more than model quality.</strong> The scoring rubric, voting mechanics, and kill switches produce better outcomes than throwing a more powerful model at an unstructured problem. Five constrained agents outperform one unconstrained agent.</p><p><strong>Autonomy is a spectrum, not a switch. </strong>The right level of autonomy depends on the task, the blast radius, and your comfort level. I give the pipeline agent full exec access. I keep the notification agent on a tight allowlist. Both are correct.</p><p><strong>Local inference is viable for production work. </strong>A 32B model on good hardware, served properly (llama.cpp, not Ollama, with enough context per slot), handles pipeline tasks reliably. You don&#8217;t need cloud APIs for everything.</p><p><strong>Your AI team will reflect your engineering discipline. </strong>If you don&#8217;t build in stall prevention, it won&#8217;t prevent stalls. If you don&#8217;t define quality gates, quality will drift. If you don&#8217;t document your governance, your agents will improvise governance&#8212;poorly.</p><p><strong>The hardest part isn&#8217;t the AI. It&#8217;s the ops. </strong>Model selection, prompt engineering, and agent design are maybe 30% of the work. The other 70% is cron scheduling, delivery routing, auth management, monitoring, and debugging why the Discord webhook stopped working at 3 AM.</p><h3>What&#8217;s Next</h3><p>The council is evaluating enterprise-tier products (an <strong>AI Agent Readiness Guide targeting IT leaders</strong>) and exploring whether the pipeline can handle longer-form content like courses. I&#8217;m also working on making the council&#8217;s own meeting transcripts and decision logs available as a teaching resource&#8212;because the most interesting thing about this system isn&#8217;t the products it ships, but the way five AI agents argue about what to build next.</p><p>If you want to build something like this, start smaller than I did. One agent, one cron job, one delivery channel. Get that working reliably before you add governance. The infrastructure complexity compounds fast.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/behind-astgl-how-i-built-an-autonomous-ai-product-team/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/behind-astgl-how-i-built-an-autonomous-ai-product-team/comments"><span>Leave a comment</span></a></p><p></p><p>James Cruce is a systems engineer and the human behind As The Geek Learns. He runs an autonomous AI product team on a Mac Studio in his home office. <strong>The council has not yet voted to replace him, but LEDGER has noted the margin improvement if they did.</strong></p><p>Technical Stack: OpenClaw v2026.4.2 &#183; Qwen3 32B (llama.cpp) &#183; Mac Studio M3 Ultra (256 GB) &#183; Discord + Slack delivery &#183; 26 cron jobs &#183; 5-agent council with IRV voting</p><p><strong>Published on As The Geek Learns&#8212;astgl.com</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://astgl.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">As The Geek Learns is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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[From Notion Export to Local Knowledge Base in One Afternoon]]></title><description><![CDATA[I hit the Export button in Notion and got a zip file.]]></description><link>https://astgl.com/p/notion-export-local-knowledge-base</link><guid isPermaLink="false">https://astgl.com/p/notion-export-local-knowledge-base</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Mon, 30 Mar 2026 01:01:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Vfxs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214408a4-e25c-403d-a625-250930972663_1024x608.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I hit the Export button in Notion and got a zip file. Three megabytes. Years of notes, content calendars, CRM records, meeting summaries, and project tracking&#8212;all flattened into Markdown and CSV files with garbled names.</p><p>Turning that export into a structured local knowledge base for an AI agent wasn&#8217;t hard. But it was full of the kind of small surprises that make you appreciate why Notion charges a subscription.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Vfxs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214408a4-e25c-403d-a625-250930972663_1024x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Vfxs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214408a4-e25c-403d-a625-250930972663_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!Vfxs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214408a4-e25c-403d-a625-250930972663_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!Vfxs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214408a4-e25c-403d-a625-250930972663_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!Vfxs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214408a4-e25c-403d-a625-250930972663_1024x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Vfxs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214408a4-e25c-403d-a625-250930972663_1024x608.png" width="1024" height="608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/214408a4-e25c-403d-a625-250930972663_1024x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:608,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Vfxs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214408a4-e25c-403d-a625-250930972663_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!Vfxs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214408a4-e25c-403d-a625-250930972663_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!Vfxs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214408a4-e25c-403d-a625-250930972663_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!Vfxs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F214408a4-e25c-403d-a625-250930972663_1024x608.png 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><figcaption class="image-caption">Knowledge Word Cloud</figcaption></figure></div><div><hr></div><h2>The Export</h2><p>Notion&#8217;s export is a zip file. Or rather, it&#8217;s a zip inside a zip. The outer archive contains an inner archive, and the inner archive contains your data. This is apparently normal. It&#8217;s also apparently undocumented.</p><p>The files inside follow Notion&#8217;s internal naming convention: every file has a 32-character hex ID appended to its name. Content Calendar 1a2b3c4d5e6f.csv instead of just Content Calendar.csv. The directory structure mirrors your Notion workspace, but the folder names have IDs too.</p><p>For 47 files, this was manageable. I organized them into a workspace structure that made sense for both me and Tars:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AEeN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed7e7e2-39f4-42a1-b458-ff464516d3ce_615x229.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AEeN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed7e7e2-39f4-42a1-b458-ff464516d3ce_615x229.png 424w, https://substackcdn.com/image/fetch/$s_!AEeN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed7e7e2-39f4-42a1-b458-ff464516d3ce_615x229.png 848w, https://substackcdn.com/image/fetch/$s_!AEeN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed7e7e2-39f4-42a1-b458-ff464516d3ce_615x229.png 1272w, https://substackcdn.com/image/fetch/$s_!AEeN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed7e7e2-39f4-42a1-b458-ff464516d3ce_615x229.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AEeN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed7e7e2-39f4-42a1-b458-ff464516d3ce_615x229.png" width="615" height="229" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ed7e7e2-39f4-42a1-b458-ff464516d3ce_615x229.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:229,&quot;width&quot;:615,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:39997,&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://astgl.com/i/192031332?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed7e7e2-39f4-42a1-b458-ff464516d3ce_615x229.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_!AEeN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed7e7e2-39f4-42a1-b458-ff464516d3ce_615x229.png 424w, https://substackcdn.com/image/fetch/$s_!AEeN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed7e7e2-39f4-42a1-b458-ff464516d3ce_615x229.png 848w, https://substackcdn.com/image/fetch/$s_!AEeN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed7e7e2-39f4-42a1-b458-ff464516d3ce_615x229.png 1272w, https://substackcdn.com/image/fetch/$s_!AEeN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed7e7e2-39f4-42a1-b458-ff464516d3ce_615x229.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Every file is Markdown or CSV. Every file lives on my SSD. Every file is readable by both ClawPad (the editor) and Tars (the agent). No database. No API. Just files.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://astgl.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">As The Geek Learns is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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><div><hr></div><h2>The CSV Gotcha</h2><p>The content calendar was the most important import. Thirty articles in various stages&#8212;ideas, drafts, ready to publish. Notion exports these as CSV with all the metadata: title, status, publish date, and tags.</p><p>My first attempt to parse it produced rows titled &#8220;Untitled&#8221; for every entry. The data was there, but the title column wasn&#8217;t matching.</p><p>The culprit: <strong>BOM (<a href="https://en.wikipedia.org/wiki/Byte_order_mark">Byte Order Mark</a>) characters.</strong> Notion&#8217;s CSV export prepends \ufeff to the beginning of the file. This invisible character attaches itself to the first column header, so Title becomes \ufeffTitle. Your code reads the header, doesn&#8217;t find a match for Title, and returns empty strings.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;b44f332b-54d0-4c78-a4c6-00384b8524b1&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml"># Wrong
with open(&#8217;calendar.csv&#8217;) as f:
 reader = csv.DictReader(f)

# Right
with open(&#8217;calendar.csv&#8217;, encoding=&#8217;utf-8-sig&#8217;) as f:
 reader = csv.DictReader(f)</code></pre></div><p>The utf-8-sig encoding strips the BOM automatically. This is a Python-specific fix&#8212;other languages have their own BOM handling. But the universal lesson is <strong>always inspect the actual bytes of imported data before writing parsing code.</strong> A head -c 20 file.csv | xxd would have shown me the BOM in seconds.</p><h2>Building the Content Pipeline</h2><p>The raw CSV became pages/astgl/pipeline.md&#8212;a living document Tars checks during every heartbeat cycle:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9cu3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F692f4792-0775-4bdf-936d-47f2420e289f_521x147.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9cu3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F692f4792-0775-4bdf-936d-47f2420e289f_521x147.png 424w, https://substackcdn.com/image/fetch/$s_!9cu3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F692f4792-0775-4bdf-936d-47f2420e289f_521x147.png 848w, https://substackcdn.com/image/fetch/$s_!9cu3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F692f4792-0775-4bdf-936d-47f2420e289f_521x147.png 1272w, https://substackcdn.com/image/fetch/$s_!9cu3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F692f4792-0775-4bdf-936d-47f2420e289f_521x147.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9cu3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F692f4792-0775-4bdf-936d-47f2420e289f_521x147.png" width="521" height="147" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/692f4792-0775-4bdf-936d-47f2420e289f_521x147.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:147,&quot;width&quot;:521,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:21624,&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://astgl.com/i/192031332?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F692f4792-0775-4bdf-936d-47f2420e289f_521x147.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_!9cu3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F692f4792-0775-4bdf-936d-47f2420e289f_521x147.png 424w, https://substackcdn.com/image/fetch/$s_!9cu3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F692f4792-0775-4bdf-936d-47f2420e289f_521x147.png 848w, https://substackcdn.com/image/fetch/$s_!9cu3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F692f4792-0775-4bdf-936d-47f2420e289f_521x147.png 1272w, https://substackcdn.com/image/fetch/$s_!9cu3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F692f4792-0775-4bdf-936d-47f2420e289f_521x147.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p></p>
      <p>
          <a href="https://astgl.com/p/notion-export-local-knowledge-base">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[I Gave My AI Agent Hands. It Immediately Started Texting My Wife.]]></title><description><![CDATA[My local AI agent, Tars, could talk.]]></description><link>https://astgl.com/p/ai-agent-hands-texting-wife</link><guid isPermaLink="false">https://astgl.com/p/ai-agent-hands-texting-wife</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Tue, 24 Mar 2026 22:31:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rNj2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70caa001-0cd2-41ed-afc7-0034f0e14432_693x871.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>My local AI agent, <strong>Tars</strong>, could talk. It could answer questions via iMessage and Slack. But it couldn&#8217;t actually <em>do</em> anything&#8212;couldn't create files, couldn&#8217;t read my calendar, couldn&#8217;t manage tasks. It was a chatbot trapped behind glass.</p><p>Phase 2 of the Notion replacement project was about giving Tars hands. Phases 3 and 4 were about teaching it what to do with them. Phase &#8220;oh no&#8221; was when it started doing things I didn&#8217;t ask for.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rNj2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70caa001-0cd2-41ed-afc7-0034f0e14432_693x871.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rNj2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70caa001-0cd2-41ed-afc7-0034f0e14432_693x871.png 424w, https://substackcdn.com/image/fetch/$s_!rNj2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70caa001-0cd2-41ed-afc7-0034f0e14432_693x871.png 848w, https://substackcdn.com/image/fetch/$s_!rNj2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70caa001-0cd2-41ed-afc7-0034f0e14432_693x871.png 1272w, https://substackcdn.com/image/fetch/$s_!rNj2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70caa001-0cd2-41ed-afc7-0034f0e14432_693x871.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rNj2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70caa001-0cd2-41ed-afc7-0034f0e14432_693x871.png" width="693" height="871" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/70caa001-0cd2-41ed-afc7-0034f0e14432_693x871.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:871,&quot;width&quot;:693,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:184934,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://astgl.com/i/191878983?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70caa001-0cd2-41ed-afc7-0034f0e14432_693x871.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_!rNj2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70caa001-0cd2-41ed-afc7-0034f0e14432_693x871.png 424w, https://substackcdn.com/image/fetch/$s_!rNj2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70caa001-0cd2-41ed-afc7-0034f0e14432_693x871.png 848w, https://substackcdn.com/image/fetch/$s_!rNj2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70caa001-0cd2-41ed-afc7-0034f0e14432_693x871.png 1272w, https://substackcdn.com/image/fetch/$s_!rNj2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70caa001-0cd2-41ed-afc7-0034f0e14432_693x871.png 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><div><hr></div><h2>From Chatbot to Agent</h2><p><a href="https://github.com/openclaw/openclaw">OpenClaw</a> ships with something called &#8220;tool profiles&#8221;&#8212;presets that control what an agent can and can&#8217;t do. Out of the box, Tars was running the messaging profile. Sounds reasonable. Here&#8217;s what that actually means:</p><p>Messaging profile: sessions_list, sessions_history, sessions_send, message</p><p>Four tools. All it could do was read and write messages. It couldn&#8217;t touch the filesystem, run commands, or use any of the skills I was about to install. I needed the full profile.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://astgl.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">As The Geek Learns is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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></p><p>I found this by reading OpenClaw&#8217;s bundled JavaScript source code. The tool profiles aren&#8217;t documented anywhere obvious&#8212;they're defined in a minified file called tool-catalog-CDe8aNjS.js. The full profile is literally an empty object: {}. No restrictions.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;json&quot;,&quot;nodeId&quot;:&quot;c11341b2-eea7-4ccc-a03b-cb962f69ec59&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-json">{
 &#8220;tools&#8221;: {
 &#8220;profile&#8221;: &#8220;full&#8221;
 }
}</code></pre></div><p>One config change, gateway restart, and Tars went from a chatbot to an autonomous agent with read, write, edit, and execute permissions on my machine.</p><p>This is the moment where self-hosting gets real. You&#8217;re not toggling a feature in a SaaS dashboard with guardrails someone else built. You&#8217;re handing your local AI unrestricted shell access. The power is exhilarating. The implications are sobering. We&#8217;ll come back to that.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Sxe2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd053339-8504-4a35-9429-386b1eb2527d_662x919.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Sxe2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd053339-8504-4a35-9429-386b1eb2527d_662x919.png 424w, https://substackcdn.com/image/fetch/$s_!Sxe2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd053339-8504-4a35-9429-386b1eb2527d_662x919.png 848w, https://substackcdn.com/image/fetch/$s_!Sxe2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd053339-8504-4a35-9429-386b1eb2527d_662x919.png 1272w, https://substackcdn.com/image/fetch/$s_!Sxe2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd053339-8504-4a35-9429-386b1eb2527d_662x919.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Sxe2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd053339-8504-4a35-9429-386b1eb2527d_662x919.png" width="662" height="919" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fd053339-8504-4a35-9429-386b1eb2527d_662x919.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:919,&quot;width&quot;:662,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:35571,&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://astgl.com/i/191878983?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd053339-8504-4a35-9429-386b1eb2527d_662x919.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_!Sxe2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd053339-8504-4a35-9429-386b1eb2527d_662x919.png 424w, https://substackcdn.com/image/fetch/$s_!Sxe2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd053339-8504-4a35-9429-386b1eb2527d_662x919.png 848w, https://substackcdn.com/image/fetch/$s_!Sxe2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd053339-8504-4a35-9429-386b1eb2527d_662x919.png 1272w, https://substackcdn.com/image/fetch/$s_!Sxe2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd053339-8504-4a35-9429-386b1eb2527d_662x919.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><div><hr></div><h2>ClawPad: The Editor That Sees What The Agent Writes</h2><p><a href="https://clawpad.io/">ClawPad</a> is a Notion-style document editor that connects to the same workspace Tars uses. When Tars creates a file at <em><strong>~/.openclaw/workspace/pages/daily-notes/2026-03-07.md</strong></em>, it shows up in ClawPad instantly. When I edit a page in ClawPad, Tars can read the changes.</p>
      <p>
          <a href="https://astgl.com/p/ai-agent-hands-texting-wife">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[I Gave My Mac Studio an AI OpenClaw Brain Upgrade. Here’s Every Wall I Hit.]]></title><description><![CDATA[Replacing Notion with a self-hosted AI agent running on a Mac Studio. Today I actually did it. The install took six hours, not the two I planned]]></description><link>https://astgl.com/p/i-gave-my-mac-studio-an-ai-openclaw</link><guid isPermaLink="false">https://astgl.com/p/i-gave-my-mac-studio-an-ai-openclaw</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Mon, 09 Mar 2026 11:32:59 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!w7x2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b394b29-24bf-4d1a-8f57-9b768221c61f_1408x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last week I said I was replacing Notion with a self-hosted AI agent running on a Mac Studio. Today I actually did it. <strong>The install took six hours, not the two I planned</strong>, and it included three problems that no documentation warned me about. The result is a working AI assistant named <strong>TARS</strong> that responds to both Slack and iMessage. <strong>All local. Zero cloud dependency.</strong></p><p>Here&#8217;s how it actually went.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!w7x2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b394b29-24bf-4d1a-8f57-9b768221c61f_1408x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!w7x2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b394b29-24bf-4d1a-8f57-9b768221c61f_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!w7x2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b394b29-24bf-4d1a-8f57-9b768221c61f_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!w7x2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b394b29-24bf-4d1a-8f57-9b768221c61f_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!w7x2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b394b29-24bf-4d1a-8f57-9b768221c61f_1408x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!w7x2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b394b29-24bf-4d1a-8f57-9b768221c61f_1408x768.png" width="1408" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5b394b29-24bf-4d1a-8f57-9b768221c61f_1408x768.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/25f8ad73-9a47-46ae-bb84-ab4def86ba67_1408x768.jpeg&quot;,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1408,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:377854,&quot;alt&quot;:&quot;\&quot;Monopoly-style game card illustration titled 'Technology Upgrade or Intellectual Leap' showing a cartoon      tycoon in a top hat and tuxedo holding a glowing brain above a robotic lobster. The scene includes gears, circuit        boards, flying birds with briefcases, a city skyline, and toy trains. The card reads 'Your robotic lobster gets a head    start! Collect Tech Bonus +$200' with the tagline 'OpenClaw Now With Brain' at the bottom.\&quot;   &quot;,&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://astgl.com/i/190225782?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25f8ad73-9a47-46ae-bb84-ab4def86ba67_1408x768.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="&quot;Monopoly-style game card illustration titled 'Technology Upgrade or Intellectual Leap' showing a cartoon      tycoon in a top hat and tuxedo holding a glowing brain above a robotic lobster. The scene includes gears, circuit        boards, flying birds with briefcases, a city skyline, and toy trains. The card reads 'Your robotic lobster gets a head    start! Collect Tech Bonus +$200' with the tagline 'OpenClaw Now With Brain' at the bottom.&quot;   " title="&quot;Monopoly-style game card illustration titled 'Technology Upgrade or Intellectual Leap' showing a cartoon      tycoon in a top hat and tuxedo holding a glowing brain above a robotic lobster. The scene includes gears, circuit        boards, flying birds with briefcases, a city skyline, and toy trains. The card reads 'Your robotic lobster gets a head    start! Collect Tech Bonus +$200' with the tagline 'OpenClaw Now With Brain' at the bottom.&quot;   " srcset="https://substackcdn.com/image/fetch/$s_!w7x2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b394b29-24bf-4d1a-8f57-9b768221c61f_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!w7x2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b394b29-24bf-4d1a-8f57-9b768221c61f_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!w7x2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b394b29-24bf-4d1a-8f57-9b768221c61f_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!w7x2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b394b29-24bf-4d1a-8f57-9b768221c61f_1408x768.png 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><figcaption class="image-caption">Collect $200 and a Brain</figcaption></figure></div><div><hr></div><h2>The Setup</h2><p>The plan was straightforward. Install Ollama for local LLM inference, install OpenClaw as the agent framework, and wire up messaging channels, done. I&#8217;ve got a Mac Studio M3 Ultra with 256 GB of unified memory. Plenty of horsepower.</p><p>Should have been a two-hour job. It wasn&#8217;t.</p><p>Not because the tools are bad. They&#8217;re actually solid. But self-hosting AI means you&#8217;re the sysadmin, the DevOps team, and the QA department all at once. Every integration has its own auth model, its own quirks, and its own way of failing without telling you.</p><div><hr></div><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://astgl.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">As The Geek Learns is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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><div><hr></div><h2>Three Problems Nobody Warned Me About</h2><p>Three problems ate most of my afternoon, and none of them were in the documentation.</p><p><strong>Problem 1: OpenClaw couldn&#8217;t authenticate with Ollama.</strong> The onboarding wizard created a config file, but the gateway runs as a macOS LaunchAgent. That&#8217;s a background service with its own environment. The API key I set in the config never reached the running process. I spent two hours reading bundled JavaScript source code before I figured it out. OpenClaw checks for an OLLAMA_API_KEY environment variable, and the LaunchAgent plist needed it injected directly.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;6cdac4a8-a7cb-4f89-8e20-12d2ea206f7f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">&lt;!-- The fix: add to ~/Library/LaunchAgents/ai.openclaw.gateway.plist --&gt;
&lt;key&gt;OLLAMA_API_KEY&lt;/key&gt;
&lt;string&gt;ollama-local&lt;/string&gt;</code></pre></div><p>The auth resolution chain goes: auth profiles.json first, then environment variables, then config apiKey. You won&#8217;t need to know that until you do.</p><div class="paywall-jump" data-component-name="PaywallToDOM"></div><p><strong>Problem 2: iMessage needs two separate permissions.</strong> OpenClaw uses imsg, a CLI tool that reads the macOS Messages database. Granting Full-Disk Access to the node binary seems like it should be enough. It&#8217;s not. The imsg binary needs its own Full-Disk Access entry too. Two binaries, two permission grants. Miss one, and you get a cryptic &#8220;permissionDenied&#8221; on chat.db with no hint about which binary is the problem.</p><p><strong>Problem 3: Slack&#8217;s event delivery broke silently.</strong> Socket Mode connected fine. The status page said everything worked. But zero messages came through. Turns out the first Slack app I created had corrupted internal state from toggling event subscriptions after initial setup. I deleted the entire app and recreated it from a YAML manifest with everything preconfigured. The second app worked immediately.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;75c8d2fb-4026-4eb4-96ab-51260f63f6e8&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml"># The manifest that actually works
settings:
 event_subscriptions:
 bot_events:
 - app_mention
 - message.im
 socket_mode_enabled: true</code></pre></div><h2>The Sequence That Actually Works</h2><p>Distilled from my trial and error so you don&#8217;t have to repeat it.</p><p><strong><a href="https://ollama.com/">Ollama</a>:</strong> Skip the install script. It needs sudo. Download Ollama.app, drag it to Applications, launch it. The CLI sets itself up automatically. Then pull your models. I&#8217;m running qwen3:32b as the primary (20 GB) with qwen3:8b as the fallback.</p><p><strong><a href="https://openclaw.ai/">OpenClaw</a>:</strong> Install via npm, run the onboarding wizard, then immediately edit the LaunchAgent plist to inject OLLAMA_API_KEY. Set contextWindow to 65536 in the config. The default 16K will break OpenClaw&#8217;s tool use, and you&#8217;ll get weird truncation errors with no obvious cause. Restart the gateway after every config change.</p><p><strong>iMessage:</strong> Grant Full Disk Access to both /path/to/node and /path/to/imsg. Add allowed senders to channels.imessage.allowFrom in E.164 format (+1XXXXXXXXXX). Don&#8217;t try messaging yourself. Messages on the same device and Apple ID don&#8217;t trigger inbound events. Use a different phone to test.</p><p><strong>Slack:</strong> Create your app from a manifest with Socket Mode and event subscriptions already configured. Don&#8217;t enable features one at a time through the UI. Generate the App-Level Token (xapp-...) with connections:write scope. Your messages arrive through the App&#8217;s Messages tab, not regular Slack DMs.</p><div><hr></div><p></p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/i-gave-my-mac-studio-an-ai-openclaw?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading As The Geek Learns! This post is public, so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/i-gave-my-mac-studio-an-ai-openclaw?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/i-gave-my-mac-studio-an-ai-openclaw?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><h2>Why This Matters</h2><p>Every one of these problems has the same root cause. Self-hosted tools don&#8217;t have managed infrastructure hiding the complexity from you. Notion works because someone else handles the auth, the message routing, and the permission grants. <strong>When you self-host, that someone is you.</strong></p><div class="pullquote"><p>Here&#8217;s what you get in return: a 32-billion-parameter language model running entirely on your hardware, responding in seconds, with zero data leaving your network. My wife texted my number, and TARS replied. I messaged it from Slack and got an answer. No API costs. No token limits. No third party reading my business documents.</p></div><p>(For the curious out there, TARS was named after the famous Interstellar TARS Marine robot and has the sarcasm as well)</p><p>First model load took 36 seconds. After that, responses come back fast. With 256 GB of unified memory, I could run models four times this size if I needed to.</p><h2>Quick Reference</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sKq3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94bb3e26-d632-4294-a942-07d562cf2410_1200x900.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sKq3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94bb3e26-d632-4294-a942-07d562cf2410_1200x900.png 424w, https://substackcdn.com/image/fetch/$s_!sKq3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94bb3e26-d632-4294-a942-07d562cf2410_1200x900.png 848w, https://substackcdn.com/image/fetch/$s_!sKq3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94bb3e26-d632-4294-a942-07d562cf2410_1200x900.png 1272w, https://substackcdn.com/image/fetch/$s_!sKq3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94bb3e26-d632-4294-a942-07d562cf2410_1200x900.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sKq3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94bb3e26-d632-4294-a942-07d562cf2410_1200x900.png" width="1200" height="900" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/94bb3e26-d632-4294-a942-07d562cf2410_1200x900.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ba819493-f35b-4113-867a-87ab0b6286bd_1200x900.png&quot;,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:900,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:68765,&quot;alt&quot;:&quot;A Quick Reference Chart for Task and Key Details for each task. Aquamarine and white letters on a black background.&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://astgl.com/i/190225782?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba819493-f35b-4113-867a-87ab0b6286bd_1200x900.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A Quick Reference Chart for Task and Key Details for each task. Aquamarine and white letters on a black background." title="A Quick Reference Chart for Task and Key Details for each task. Aquamarine and white letters on a black background." srcset="https://substackcdn.com/image/fetch/$s_!sKq3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94bb3e26-d632-4294-a942-07d562cf2410_1200x900.png 424w, https://substackcdn.com/image/fetch/$s_!sKq3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94bb3e26-d632-4294-a942-07d562cf2410_1200x900.png 848w, https://substackcdn.com/image/fetch/$s_!sKq3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94bb3e26-d632-4294-a942-07d562cf2410_1200x900.png 1272w, https://substackcdn.com/image/fetch/$s_!sKq3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94bb3e26-d632-4294-a942-07d562cf2410_1200x900.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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/i-gave-my-mac-studio-an-ai-openclaw/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/i-gave-my-mac-studio-an-ai-openclaw/comments"><span>Leave a comment</span></a></p><p></p><p>This is Part 2 of the Notion Replacement series. <a href="https://astgl.com/p/replacing-notion-openclaw-self-hosted-ai">Part 1</a> covered why I&#8217;m making the switch.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;283343de-de91-4007-9027-73f6b66fe9ec&quot;,&quot;caption&quot;:&quot;Today I&#8217;m starting a project I&#8217;ve been thinking about for weeks: ripping Notion out of my workflow and replacing it with OpenClaw, a self-hosted AI agent framework running entirely on my Mac Studio. No cloud. No subscription. No black box.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;I&#8217;m Replacing Notion With a Self-Hosted AI Agent. Here&#8217;s Why.&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:421133477,&quot;name&quot;:&quot;James Cruce&quot;,&quot;bio&quot;:null,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!T5FD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd6a6400-f0cd-4ff3-8541-f6cccf4d9a87_400x400.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-03-06T19:01:12.665Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!zPhv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d1b4e6-0faf-4cbd-94ca-705a15197022_1200x675.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://astgl.com/p/replacing-notion-openclaw-self-hosted-ai&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:190114952,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:7173322,&quot;publication_name&quot;:&quot;As The Geek Learns&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!hfS3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b53b6e-8c71-473a-be58-79403cf36d59_256x256.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p> Next up: Part 3, installing the document editor. Follow along at As The Geek Learns.</p>]]></content:encoded></item><item><title><![CDATA[I’m Replacing Notion With a Self-Hosted AI Agent. Here’s Why.]]></title><description><![CDATA[Episode 007]]></description><link>https://astgl.com/p/im-replacing-notion-with-a-self-hosted</link><guid isPermaLink="false">https://astgl.com/p/im-replacing-notion-with-a-self-hosted</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Fri, 06 Mar 2026 19:06:55 GMT</pubDate><enclosure url="https://api.substack.com/feed/podcast/190135284/6ebc0d00689b0a816345aaa108e3f286.mp3" length="0" type="audio/mpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ieWQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F277f0718-12de-4c14-80cb-0d2b764d7772_201x251.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ieWQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F277f0718-12de-4c14-80cb-0d2b764d7772_201x251.png 424w, https://substackcdn.com/image/fetch/$s_!ieWQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F277f0718-12de-4c14-80cb-0d2b764d7772_201x251.png 848w, https://substackcdn.com/image/fetch/$s_!ieWQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F277f0718-12de-4c14-80cb-0d2b764d7772_201x251.png 1272w, https://substackcdn.com/image/fetch/$s_!ieWQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F277f0718-12de-4c14-80cb-0d2b764d7772_201x251.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ieWQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F277f0718-12de-4c14-80cb-0d2b764d7772_201x251.png" width="201" height="251" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/277f0718-12de-4c14-80cb-0d2b764d7772_201x251.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:251,&quot;width&quot;:201,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8446,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://astgl.com/i/190135284?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F277f0718-12de-4c14-80cb-0d2b764d7772_201x251.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_!ieWQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F277f0718-12de-4c14-80cb-0d2b764d7772_201x251.png 424w, https://substackcdn.com/image/fetch/$s_!ieWQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F277f0718-12de-4c14-80cb-0d2b764d7772_201x251.png 848w, https://substackcdn.com/image/fetch/$s_!ieWQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F277f0718-12de-4c14-80cb-0d2b764d7772_201x251.png 1272w, https://substackcdn.com/image/fetch/$s_!ieWQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F277f0718-12de-4c14-80cb-0d2b764d7772_201x251.png 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><p>Today I&#8217;m starting a project I&#8217;ve been thinking about for weeks: ripping Notion out of my workflow and replacing it with <a href="https://openclaw.ai/">OpenClaw</a>, a self-hosted AI agent framework running entirely on my Mac Studio. No cloud. No subscription. No black box.</p><p>This sounds dramatic. It kind of is. But the reasons are practical.</p>]]></content:encoded></item><item><title><![CDATA[I’m Replacing Notion With a Self-Hosted AI Agent. Here’s Why.]]></title><description><![CDATA[Today I&#8217;m starting a project I&#8217;ve been thinking about for weeks: ripping Notion out of my workflow and replacing it with OpenClaw, a self-hosted AI agent framework running entirely on my Mac Studio.]]></description><link>https://astgl.com/p/replacing-notion-openclaw-self-hosted-ai</link><guid isPermaLink="false">https://astgl.com/p/replacing-notion-openclaw-self-hosted-ai</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Fri, 06 Mar 2026 19:01:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!zPhv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d1b4e6-0faf-4cbd-94ca-705a15197022_1200x675.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today I&#8217;m starting a project I&#8217;ve been thinking about for weeks: ripping Notion out of my workflow and replacing it with <a href="https://openclaw.ai/">OpenClaw</a>, a self-hosted AI agent framework running entirely on my Mac Studio. No cloud. No subscription. No black box.</p><p>This sounds dramatic. It kind of is. But the reasons are practical.</p><h2>The Setup</h2><p>Notion is good software. I&#8217;ve used it for years for daily notes, content pipelines, project tracking, and knowledge bases. It does enough things well enough that you stop questioning the monthly charge.</p><p>But &#8220;well enough&#8221; started feeling like a ceiling.</p><p>I&#8217;m paying a recurring subscription for what amounts to a document editor with a database bolted on. The AI features cost extra. The data lives on someone else&#8217;s servers. And that charge hits every month whether I used Notion heavily or barely opened it.</p><p>When you&#8217;re building side projects and running a content platform, every recurring cost needs to justify itself. Notion stopped clearing that bar, not because it got worse, but because the alternatives got better.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zPhv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d1b4e6-0faf-4cbd-94ca-705a15197022_1200x675.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zPhv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d1b4e6-0faf-4cbd-94ca-705a15197022_1200x675.png 424w, https://substackcdn.com/image/fetch/$s_!zPhv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d1b4e6-0faf-4cbd-94ca-705a15197022_1200x675.png 848w, https://substackcdn.com/image/fetch/$s_!zPhv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d1b4e6-0faf-4cbd-94ca-705a15197022_1200x675.png 1272w, https://substackcdn.com/image/fetch/$s_!zPhv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d1b4e6-0faf-4cbd-94ca-705a15197022_1200x675.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zPhv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d1b4e6-0faf-4cbd-94ca-705a15197022_1200x675.png" width="1200" height="675" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/36d1b4e6-0faf-4cbd-94ca-705a15197022_1200x675.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d2337c62-a723-482e-a87a-f8a0cebd3cc1_1200x675.png&quot;,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:675,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:44135,&quot;alt&quot;:&quot;A dark navy split-screen comparison image. The left side is labeled \&quot;NOTION\&quot; in red with \&quot;Cloud SaaS\&quot; underneath, showing a cloud icon and five bullet points in red: $X/month forever, data on their servers, AI with usage caps, reactive (you go to it), and vendor lock-in. The right side is labeled \&quot;OPENCLAW\&quot; in green with \&quot;Self-Hosted Local\&quot; underneath, showing a server rack icon with green status lights and five bullet points in green: $0/month (hardware owned), Markdown on your SSD, unlimited local LLMs, proactive (it comes to you), and plain files you own. An orange arrow points from left to right. The bottom reads \&quot;Going Local\&quot; in orange with As The Geek Learns branding.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://astgl.com/i/190114952?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2337c62-a723-482e-a87a-f8a0cebd3cc1_1200x675.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A dark navy split-screen comparison image. The left side is labeled &quot;NOTION&quot; in red with &quot;Cloud SaaS&quot; underneath, showing a cloud icon and five bullet points in red: $X/month forever, data on their servers, AI with usage caps, reactive (you go to it), and vendor lock-in. The right side is labeled &quot;OPENCLAW&quot; in green with &quot;Self-Hosted Local&quot; underneath, showing a server rack icon with green status lights and five bullet points in green: $0/month (hardware owned), Markdown on your SSD, unlimited local LLMs, proactive (it comes to you), and plain files you own. An orange arrow points from left to right. The bottom reads &quot;Going Local&quot; in orange with As The Geek Learns branding." title="A dark navy split-screen comparison image. The left side is labeled &quot;NOTION&quot; in red with &quot;Cloud SaaS&quot; underneath, showing a cloud icon and five bullet points in red: $X/month forever, data on their servers, AI with usage caps, reactive (you go to it), and vendor lock-in. The right side is labeled &quot;OPENCLAW&quot; in green with &quot;Self-Hosted Local&quot; underneath, showing a server rack icon with green status lights and five bullet points in green: $0/month (hardware owned), Markdown on your SSD, unlimited local LLMs, proactive (it comes to you), and plain files you own. An orange arrow points from left to right. The bottom reads &quot;Going Local&quot; in orange with As The Geek Learns branding." srcset="https://substackcdn.com/image/fetch/$s_!zPhv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d1b4e6-0faf-4cbd-94ca-705a15197022_1200x675.png 424w, https://substackcdn.com/image/fetch/$s_!zPhv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d1b4e6-0faf-4cbd-94ca-705a15197022_1200x675.png 848w, https://substackcdn.com/image/fetch/$s_!zPhv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d1b4e6-0faf-4cbd-94ca-705a15197022_1200x675.png 1272w, https://substackcdn.com/image/fetch/$s_!zPhv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36d1b4e6-0faf-4cbd-94ca-705a15197022_1200x675.png 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><figcaption class="image-caption">Going LLM Local</figcaption></figure></div><div><hr></div><h2>What&#8217;s Actually Going On</h2><p>The subscription cost is the easy argument. The real one goes deeper.</p><p>I&#8217;ve spent most of my IT career building and managing infrastructure. What I&#8217;m learning now is how to build things: software, AI workflows, and automation pipelines. Running a local AI agent isn&#8217;t just about replacing a SaaS tool. It&#8217;s about understanding how these systems work under the hood.</p><p>When you use Notion AI, you&#8217;re calling an API you can&#8217;t see, running a model you can&#8217;t inspect, with prompts you didn&#8217;t write. It works. You learn nothing.</p><p>When you run your own agent on your own hardware with your own models, every layer is visible. You see the prompts. You see the model responses. You see where tool calls succeed and where they fail. You understand why the system behaves the way it does.</p><p>For someone building AI-assisted tools and writing about the experience, that visibility isn&#8217;t optional. It&#8217;s the whole point.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://astgl.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">As The Geek Learns is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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><div><hr></div><h2>The Fix</h2><p>Here&#8217;s the stack I&#8217;m building:</p><p><strong><a href="https://openclaw.ai/">OpenClaw</a></strong> handles the agent framework, the brain that orchestrates everything. It runs as a background service on macOS, accepts messages via iMessage, and acts proactively on a schedule without being prompted.</p><p><strong><a href="https://ollama.com/">Ollama</a></strong> provides local LLM inference. Models run on the Mac Studio&#8217;s M3 Ultra with 256 GB of unified memory. No API calls to OpenAI. No per-token charges. No rate limits.</p><p><strong><a href="https://www.clawpad.ai/">ClawPad</a></strong> gives me a Notion-style editor that reads and writes the same Markdown files the agent uses.</p><p><strong><a href="https://anythingllm.com/">AnythingLLM</a></strong> adds RAG (Retrieval-Augmented Generation) so the agent can search and reason over my entire knowledge base locally.</p><p>Everything runs on localhost. Nothing phones home.</p><p>The piece that most exceeds Notion is <strong>HEARTBEAT.md</strong>. It is a file of standing instructions the agent executes on a schedule. </p><p>Every morning at 6:30, it creates my daily note, checks my calendar, pulls open tasks, and pushes a briefing to my iPhone via iMessage. Every evening, it summarizes the day.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hC6F!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47e0d3f4-e69e-43b8-ae6e-ed258685febe_600x432.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hC6F!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47e0d3f4-e69e-43b8-ae6e-ed258685febe_600x432.png 424w, https://substackcdn.com/image/fetch/$s_!hC6F!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47e0d3f4-e69e-43b8-ae6e-ed258685febe_600x432.png 848w, https://substackcdn.com/image/fetch/$s_!hC6F!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47e0d3f4-e69e-43b8-ae6e-ed258685febe_600x432.png 1272w, https://substackcdn.com/image/fetch/$s_!hC6F!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47e0d3f4-e69e-43b8-ae6e-ed258685febe_600x432.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hC6F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47e0d3f4-e69e-43b8-ae6e-ed258685febe_600x432.png" width="600" height="432" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/47e0d3f4-e69e-43b8-ae6e-ed258685febe_600x432.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:432,&quot;width&quot;:600,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:32067,&quot;alt&quot;:&quot;A side-by-side flowchart comparing two morning workflows. On the Notion side, labeled \&quot;Reactive,\&quot; the steps are: you wake up, open Notion, scroll to find tasks, check calendar separately, and organize your own day &#8212; all shown in red. On the OpenClaw side, labeled \&quot;Proactive,\&quot; the steps are: 6:30 AM heartbeat fires, agent creates daily note, agent checks calendar, agent pulls open tasks, and briefing pushed to iPhone &#8212; all shown in green. The key difference: you go to Notion, but OpenClaw comes to 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://astgl.com/i/190114952?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47e0d3f4-e69e-43b8-ae6e-ed258685febe_600x432.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A side-by-side flowchart comparing two morning workflows. On the Notion side, labeled &quot;Reactive,&quot; the steps are: you wake up, open Notion, scroll to find tasks, check calendar separately, and organize your own day &#8212; all shown in red. On the OpenClaw side, labeled &quot;Proactive,&quot; the steps are: 6:30 AM heartbeat fires, agent creates daily note, agent checks calendar, agent pulls open tasks, and briefing pushed to iPhone &#8212; all shown in green. The key difference: you go to Notion, but OpenClaw comes to you." title="A side-by-side flowchart comparing two morning workflows. On the Notion side, labeled &quot;Reactive,&quot; the steps are: you wake up, open Notion, scroll to find tasks, check calendar separately, and organize your own day &#8212; all shown in red. On the OpenClaw side, labeled &quot;Proactive,&quot; the steps are: 6:30 AM heartbeat fires, agent creates daily note, agent checks calendar, agent pulls open tasks, and briefing pushed to iPhone &#8212; all shown in green. The key difference: you go to Notion, but OpenClaw comes to you." srcset="https://substackcdn.com/image/fetch/$s_!hC6F!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47e0d3f4-e69e-43b8-ae6e-ed258685febe_600x432.png 424w, https://substackcdn.com/image/fetch/$s_!hC6F!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47e0d3f4-e69e-43b8-ae6e-ed258685febe_600x432.png 848w, https://substackcdn.com/image/fetch/$s_!hC6F!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47e0d3f4-e69e-43b8-ae6e-ed258685febe_600x432.png 1272w, https://substackcdn.com/image/fetch/$s_!hC6F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47e0d3f4-e69e-43b8-ae6e-ed258685febe_600x432.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">You go to Notion. OpenClaw comes to you.</figcaption></figure></div><p>I didn&#8217;t open anything. I didn&#8217;t remember to check my task list. The workspace came to me.</p><p>If you&#8217;ve heard me say, <strong>&#8220;If I do something more than twice, automate it,&#8221; </strong>this is that philosophy taken to its logical conclusion.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ea6f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b60428d-d0e3-4f66-96b4-4e67f8c1a61a_600x208.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ea6f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b60428d-d0e3-4f66-96b4-4e67f8c1a61a_600x208.png 424w, https://substackcdn.com/image/fetch/$s_!ea6f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b60428d-d0e3-4f66-96b4-4e67f8c1a61a_600x208.png 848w, https://substackcdn.com/image/fetch/$s_!ea6f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b60428d-d0e3-4f66-96b4-4e67f8c1a61a_600x208.png 1272w, https://substackcdn.com/image/fetch/$s_!ea6f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b60428d-d0e3-4f66-96b4-4e67f8c1a61a_600x208.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ea6f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b60428d-d0e3-4f66-96b4-4e67f8c1a61a_600x208.png" width="600" height="208" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1b60428d-d0e3-4f66-96b4-4e67f8c1a61a_600x208.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:208,&quot;width&quot;:600,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19366,&quot;alt&quot;:&quot;A diagram showing how all components of the self-hosted OpenClaw stack connect on a Mac Studio. An iPhone or iPad sends messages via iMessage to the OpenClaw Gateway on port 18789. The gateway connects to three services: ClawPad editor on port 3333, Open WebUI on port 3000, and AnythingLLM on port 3001. All three services route to Ollama for local LLM inference on port 11434, which runs on the Mac Studio M3 Ultra with 256 GB of unified memory. Everything runs on localhost.&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://astgl.com/i/190114952?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b60428d-d0e3-4f66-96b4-4e67f8c1a61a_600x208.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A diagram showing how all components of the self-hosted OpenClaw stack connect on a Mac Studio. An iPhone or iPad sends messages via iMessage to the OpenClaw Gateway on port 18789. The gateway connects to three services: ClawPad editor on port 3333, Open WebUI on port 3000, and AnythingLLM on port 3001. All three services route to Ollama for local LLM inference on port 11434, which runs on the Mac Studio M3 Ultra with 256 GB of unified memory. Everything runs on localhost." title="A diagram showing how all components of the self-hosted OpenClaw stack connect on a Mac Studio. An iPhone or iPad sends messages via iMessage to the OpenClaw Gateway on port 18789. The gateway connects to three services: ClawPad editor on port 3333, Open WebUI on port 3000, and AnythingLLM on port 3001. All three services route to Ollama for local LLM inference on port 11434, which runs on the Mac Studio M3 Ultra with 256 GB of unified memory. Everything runs on localhost." srcset="https://substackcdn.com/image/fetch/$s_!ea6f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b60428d-d0e3-4f66-96b4-4e67f8c1a61a_600x208.png 424w, https://substackcdn.com/image/fetch/$s_!ea6f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b60428d-d0e3-4f66-96b4-4e67f8c1a61a_600x208.png 848w, https://substackcdn.com/image/fetch/$s_!ea6f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b60428d-d0e3-4f66-96b4-4e67f8c1a61a_600x208.png 1272w, https://substackcdn.com/image/fetch/$s_!ea6f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b60428d-d0e3-4f66-96b4-4e67f8c1a61a_600x208.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Everything runs on localhost. Nothing phones home.</figcaption></figure></div><div><hr></div><h2>Why This Matters</h2><p>I&#8217;d be dishonest if I skipped the security reality. OpenClaw&#8217;s track record here is horrendous.</p><p>In February 2026, researchers found over 135,000 OpenClaw instances exposed to the public internet. Over 15,000 were vulnerable to remote code execution. A coordinated attack called <strong><a href="https://cybersecuritynews.com/clawhavoc-poisoned-openclaws-clawhub/">&#8220;ClawHavoc&#8221;</a></strong> planted more than a thousand malicious plugins on the community registry. Nine CVEs have been disclosed, including one for SSH command injection on macOS specifically.</p><p>An AI agent with shell access to your machine, running 24/7, is a serious attack surface if you don&#8217;t lock it down. Running local means you own the security. That&#8217;s both the benefit and the burden.</p><p>The <strong><a href="https://github.com/openclaw/openclaw/releases/tag/v2026.3.2">latest release (v2026.3.2)</a></strong> defaults to loopback-only binding, adds credential management through macOS Keychain, and includes SSRF protection. The posture is dramatically better than a month ago. But &#8220;better&#8221; doesn&#8217;t mean &#8220;done.&#8221;</p><p>And the tradeoffs beyond security are real too. Notion&#8217;s relational databases are genuinely useful. Markdown with YAML front matter is functional but not elegant. The mobile experience goes from Notion&#8217;s polished iOS app to iMessage commands. Maintenance is on me. Sharing doesn&#8217;t exist.</p><p>For a solo practitioner building AI-assisted tools, the math works. For a team that needs collaboration, probably not.</p><div><hr></div><h2>Quick Reference</h2><h3>What I&#8217;m gaining:</h3><p>Zero recurring cost. Hardware is already paid for, and the software is open source.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IncD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f03899f-f5d0-418d-980a-63066aca2cf9_1200x675.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IncD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f03899f-f5d0-418d-980a-63066aca2cf9_1200x675.png 424w, https://substackcdn.com/image/fetch/$s_!IncD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f03899f-f5d0-418d-980a-63066aca2cf9_1200x675.png 848w, https://substackcdn.com/image/fetch/$s_!IncD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f03899f-f5d0-418d-980a-63066aca2cf9_1200x675.png 1272w, https://substackcdn.com/image/fetch/$s_!IncD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f03899f-f5d0-418d-980a-63066aca2cf9_1200x675.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IncD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f03899f-f5d0-418d-980a-63066aca2cf9_1200x675.png" width="1200" height="675" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7f03899f-f5d0-418d-980a-63066aca2cf9_1200x675.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/de6a816e-e1a5-4038-a2d2-a53d1ee7d28f_1200x675.png&quot;,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:675,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:29282,&quot;alt&quot;:&quot;A timeline chart titled \&quot;The Cost Equation\&quot; comparing Notion and OpenClaw costs over 12 months. Notion is represented by repeating red bars along the timeline, each marked with a dollar sign, labeled \&quot;forever\&quot; &#8212; the subscription never stops. OpenClaw shows a single green \&quot;Paid\&quot; marker for hardware already owned, then a flat green line at $0/month extending across the entire timeline. A callout box in orange reads \&quot;After 12 months: $XX saved vs $0 spent.\&quot; The horizontal axis shows months M1 through M12 with an arrow continuing into the future.&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://astgl.com/i/190114952?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde6a816e-e1a5-4038-a2d2-a53d1ee7d28f_1200x675.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A timeline chart titled &quot;The Cost Equation&quot; comparing Notion and OpenClaw costs over 12 months. Notion is represented by repeating red bars along the timeline, each marked with a dollar sign, labeled &quot;forever&quot; &#8212; the subscription never stops. OpenClaw shows a single green &quot;Paid&quot; marker for hardware already owned, then a flat green line at $0/month extending across the entire timeline. A callout box in orange reads &quot;After 12 months: $XX saved vs $0 spent.&quot; The horizontal axis shows months M1 through M12 with an arrow continuing into the future." title="A timeline chart titled &quot;The Cost Equation&quot; comparing Notion and OpenClaw costs over 12 months. Notion is represented by repeating red bars along the timeline, each marked with a dollar sign, labeled &quot;forever&quot; &#8212; the subscription never stops. OpenClaw shows a single green &quot;Paid&quot; marker for hardware already owned, then a flat green line at $0/month extending across the entire timeline. A callout box in orange reads &quot;After 12 months: $XX saved vs $0 spent.&quot; The horizontal axis shows months M1 through M12 with an arrow continuing into the future." srcset="https://substackcdn.com/image/fetch/$s_!IncD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f03899f-f5d0-418d-980a-63066aca2cf9_1200x675.png 424w, https://substackcdn.com/image/fetch/$s_!IncD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f03899f-f5d0-418d-980a-63066aca2cf9_1200x675.png 848w, https://substackcdn.com/image/fetch/$s_!IncD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f03899f-f5d0-418d-980a-63066aca2cf9_1200x675.png 1272w, https://substackcdn.com/image/fetch/$s_!IncD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f03899f-f5d0-418d-980a-63066aca2cf9_1200x675.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">Zero Recurring Cost</figcaption></figure></div><p></p><p>Complete data ownership. Every document is a Markdown file on my SSD.</p><p>Unlimited AI. No usage caps and no &#8220;you&#8217;ve exceeded your credits.&#8221;</p><p>Proactive workspace. Morning briefings, auto daily notes, and task reminders via iMessage.</p><p>Deep understanding. Every layer is visible, and every configuration is mine.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0IWM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F722781ee-71fe-4005-aaa9-f3776bd52d75_1200x675.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0IWM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F722781ee-71fe-4005-aaa9-f3776bd52d75_1200x675.png 424w, https://substackcdn.com/image/fetch/$s_!0IWM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F722781ee-71fe-4005-aaa9-f3776bd52d75_1200x675.png 848w, https://substackcdn.com/image/fetch/$s_!0IWM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F722781ee-71fe-4005-aaa9-f3776bd52d75_1200x675.png 1272w, https://substackcdn.com/image/fetch/$s_!0IWM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F722781ee-71fe-4005-aaa9-f3776bd52d75_1200x675.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0IWM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F722781ee-71fe-4005-aaa9-f3776bd52d75_1200x675.png" width="1200" height="675" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/722781ee-71fe-4005-aaa9-f3776bd52d75_1200x675.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2c63c04f-db67-46ab-a49c-aa52499e8b22_1200x675.png&quot;,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:675,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:60648,&quot;alt&quot;:&quot;An infographic titled \&quot;The Visibility Gap\&quot; comparing how Notion AI and a local agent handle requests. The left column, labeled \&quot;Notion AI\&quot; in red, shows a flow from \&quot;You type a prompt\&quot; through three opaque red boxes with hatching and X marks: hidden prompt engineering, unknown model, and can't see tool calls, ending at \&quot;Response appears.\&quot; The tagline reads \&quot;It works. You learn nothing.\&quot; The right column, labeled \&quot;Local Agent\&quot; in green, shows the same flow but with transparent green boxes and checkmarks: your prompt (you wrote it), your model (qwen3:32b), your tool calls (visible), your config (AGENTS.md), and response plus full trace. The tagline reads \&quot;Every layer visible. You learn everything.\&quot;&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://astgl.com/i/190114952?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c63c04f-db67-46ab-a49c-aa52499e8b22_1200x675.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="An infographic titled &quot;The Visibility Gap&quot; comparing how Notion AI and a local agent handle requests. The left column, labeled &quot;Notion AI&quot; in red, shows a flow from &quot;You type a prompt&quot; through three opaque red boxes with hatching and X marks: hidden prompt engineering, unknown model, and can't see tool calls, ending at &quot;Response appears.&quot; The tagline reads &quot;It works. You learn nothing.&quot; The right column, labeled &quot;Local Agent&quot; in green, shows the same flow but with transparent green boxes and checkmarks: your prompt (you wrote it), your model (qwen3:32b), your tool calls (visible), your config (AGENTS.md), and response plus full trace. The tagline reads &quot;Every layer visible. You learn everything.&quot;" title="An infographic titled &quot;The Visibility Gap&quot; comparing how Notion AI and a local agent handle requests. The left column, labeled &quot;Notion AI&quot; in red, shows a flow from &quot;You type a prompt&quot; through three opaque red boxes with hatching and X marks: hidden prompt engineering, unknown model, and can't see tool calls, ending at &quot;Response appears.&quot; The tagline reads &quot;It works. You learn nothing.&quot; The right column, labeled &quot;Local Agent&quot; in green, shows the same flow but with transparent green boxes and checkmarks: your prompt (you wrote it), your model (qwen3:32b), your tool calls (visible), your config (AGENTS.md), and response plus full trace. The tagline reads &quot;Every layer visible. You learn everything.&quot;" srcset="https://substackcdn.com/image/fetch/$s_!0IWM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F722781ee-71fe-4005-aaa9-f3776bd52d75_1200x675.png 424w, https://substackcdn.com/image/fetch/$s_!0IWM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F722781ee-71fe-4005-aaa9-f3776bd52d75_1200x675.png 848w, https://substackcdn.com/image/fetch/$s_!0IWM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F722781ee-71fe-4005-aaa9-f3776bd52d75_1200x675.png 1272w, https://substackcdn.com/image/fetch/$s_!0IWM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F722781ee-71fe-4005-aaa9-f3776bd52d75_1200x675.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">Black Box to Visible Box</figcaption></figure></div><h3><strong>What I&#8217;m giving up:</strong></h3><p>Relational databases with filtered views.</p><p>Polished mobile app.</p><p>Zero-maintenance experience.</p><p>Team collaboration.</p><p>The plan is six weeks, phased. Each phase leaves a working system. If it fails, Notion re-imports Markdown. The escape hatch stays open.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2AyM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F401ad125-967c-4f00-b687-0121e231ba7a_1200x675.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2AyM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F401ad125-967c-4f00-b687-0121e231ba7a_1200x675.png 424w, https://substackcdn.com/image/fetch/$s_!2AyM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F401ad125-967c-4f00-b687-0121e231ba7a_1200x675.png 848w, https://substackcdn.com/image/fetch/$s_!2AyM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F401ad125-967c-4f00-b687-0121e231ba7a_1200x675.png 1272w, https://substackcdn.com/image/fetch/$s_!2AyM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F401ad125-967c-4f00-b687-0121e231ba7a_1200x675.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2AyM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F401ad125-967c-4f00-b687-0121e231ba7a_1200x675.png" width="1200" height="675" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/401ad125-967c-4f00-b687-0121e231ba7a_1200x675.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/28a6fc89-64b2-489a-8b64-3b0be8f25261_1200x675.png&quot;,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:675,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:44541,&quot;alt&quot;:&quot;A timeline chart titled \&quot;Notion to OpenClaw &#8212; 6-Week Migration\&quot; showing four color-coded phases as horizontal bars progressing left to right. Foundation (green) covers Ollama, OpenClaw, and security setup in three days, then ClawPad editor in three more. Core Skills (blue) adds tasks, calendar, and reminders over four days, then the heartbeat proactive agent over four more. Migration (purple) includes knowledge base and RAG setup over seven days, then pipelines and workflows over eight days. Validation (orange) runs a parallel comparison and go/no-go decision over seven days. A clean timeline at the bottom spans from March 6 to April 5 with \&quot;6 weeks\&quot; labeled in the center. Each bar shows its duration in days.&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://astgl.com/i/190114952?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28a6fc89-64b2-489a-8b64-3b0be8f25261_1200x675.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A timeline chart titled &quot;Notion to OpenClaw &#8212; 6-Week Migration&quot; showing four color-coded phases as horizontal bars progressing left to right. Foundation (green) covers Ollama, OpenClaw, and security setup in three days, then ClawPad editor in three more. Core Skills (blue) adds tasks, calendar, and reminders over four days, then the heartbeat proactive agent over four more. Migration (purple) includes knowledge base and RAG setup over seven days, then pipelines and workflows over eight days. Validation (orange) runs a parallel comparison and go/no-go decision over seven days. A clean timeline at the bottom spans from March 6 to April 5 with &quot;6 weeks&quot; labeled in the center. Each bar shows its duration in days." title="A timeline chart titled &quot;Notion to OpenClaw &#8212; 6-Week Migration&quot; showing four color-coded phases as horizontal bars progressing left to right. Foundation (green) covers Ollama, OpenClaw, and security setup in three days, then ClawPad editor in three more. Core Skills (blue) adds tasks, calendar, and reminders over four days, then the heartbeat proactive agent over four more. Migration (purple) includes knowledge base and RAG setup over seven days, then pipelines and workflows over eight days. Validation (orange) runs a parallel comparison and go/no-go decision over seven days. A clean timeline at the bottom spans from March 6 to April 5 with &quot;6 weeks&quot; labeled in the center. Each bar shows its duration in days." srcset="https://substackcdn.com/image/fetch/$s_!2AyM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F401ad125-967c-4f00-b687-0121e231ba7a_1200x675.png 424w, https://substackcdn.com/image/fetch/$s_!2AyM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F401ad125-967c-4f00-b687-0121e231ba7a_1200x675.png 848w, https://substackcdn.com/image/fetch/$s_!2AyM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F401ad125-967c-4f00-b687-0121e231ba7a_1200x675.png 1272w, https://substackcdn.com/image/fetch/$s_!2AyM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F401ad125-967c-4f00-b687-0121e231ba7a_1200x675.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">Each phase leaves a working system. The escape hatch stays open.</figcaption></figure></div><p></p><p>I&#8217;ll document every win, frustration, configuration gotcha, and security decision along the way. Not a polished demo, but an honest account of replacing a mature SaaS product with open-source infrastructure you run yourself.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/replacing-notion-openclaw-self-hosted-ai/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/replacing-notion-openclaw-self-hosted-ai/comments"><span>Leave a comment</span></a></p><div><hr></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/replacing-notion-openclaw-self-hosted-ai?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading As The Geek Learns! This post is public, so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/replacing-notion-openclaw-self-hosted-ai?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/replacing-notion-openclaw-self-hosted-ai?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><p><em>Found this useful? I share practical lessons from my systems engineering journey at <a href="https://astgl.com">As The Geek Learns</a>.</em></p>]]></content:encoded></item><item><title><![CDATA[Cortex: An Event-Sourced Memory Architecture for AI Coding Assistants]]></title><description><![CDATA[As The Geek Learns | Technical Deep Dive Author: James Cruce Date: February 2026]]></description><link>https://astgl.com/p/cortex-an-event-sourced-memory-architecture</link><guid isPermaLink="false">https://astgl.com/p/cortex-an-event-sourced-memory-architecture</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Tue, 17 Feb 2026 23:01:09 GMT</pubDate><enclosure url="https://api.substack.com/feed/podcast/188280947/f02af86af017a3815e57065a31f64a7d.mp3" length="0" type="audio/mpeg"/><content:encoded><![CDATA[<p><strong>Cortex: Event-Sourced Memory for AI Coding Assistants</strong></p><p><strong>Episode Summary</strong></p><p>Every time you close a session with an AI coding assistant, it forgets everything&#8212;the architecture it mapped out, the approaches it rejected, and the plan it was halfway through executing. You become the memory system. Cortex is an event-sourced memory architecture designed to fix that. In this episode, we walk through the problem, the research process that led to the solution, how the system works across four progressive tiers, and real-world A/B testing results that show an 84% reduction in cold start time and 80% fewer decision regressions.</p><p><strong>Suggested Episode Segments</strong></p><ul><li><p>00:00&#8212;Intro: The amnesia problem with AI coding assistants</p></li><li><p>01:22&#8212;What actually gets lost between sessions (five categories)</p></li><li><p>03:26&#8212;Why event sourcing is the right foundation</p></li><li><p>05:32&#8212;Three-layer extraction: structural, semantic, and self-reporting</p></li><li><p>07:24&#8212;Projected briefings and decision immortality</p></li><li><p>08:59&#8212;Progressive tiers: from 30-second setup to full MCP server</p></li><li><p>12:13&#8212;A/B testing results and what surprised us</p></li><li><p>12:43&#8212;Implementation war stories and gotchas</p></li><li><p>13:03&#8212;The meta-irony of building this with a forgetful AI</p></li><li><p>13:40&#8212;Tier 3: MCP server, git-tracked projections, branch alignment</p></li><li><p>14:59&#8212;Getting started and what&#8217;s next</p></li></ul><p><strong>The Problem</strong></p><p>AI coding assistants like Claude lose five categories of context at session boundaries: architectural understanding built through exploration (10-30 minutes of re-exploration per session), decision history including rejected approaches and reasoning, work state like multi-step plans and progress, tool and environment state, and conversational nuance&#8212;your preferences, priorities, and communication style. The cruelest part is that the better the AI performs within a session, the more painful the loss when that session ends.</p><p><strong>The Solution</strong></p><p>Cortex applies event sourcing&#8212;an immutable, append-only pattern borrowed from distributed systems&#8212;to capture and preserve context automatically. Three innovations make it work.</p><p>First, three-layer event extraction. Layer 1 parses Claude Code hook payloads for objective structural data like file reads, commands, and code modifications&#8212;100% accuracy within its scope. Layer 2 pattern-matches response text for decision markers with confidence scoring. Layer 3 lets Claude self-report important context using <code>[MEMORY:]</code> tags, offering the highest accuracy through deliberate intent. These independent extractors compose through aggregation rather than requiring one monolithic system.</p><p>Second, projected briefings. Raw event replay would blow through token budgets, so Cortex generates compressed, token-aware briefings that default to about 2,000 tokens&#8212;roughly 0.1% of the context window. Active decisions are immortal and never decay. Current plans show progress with step status. Recent knowledge fades over sessions based on tactical relevance. This separates retention (store everything) from representation (surface what matters).</p><p>Third, progressive tiers. Tier 0 gives you basic context capture in 30 seconds. Tier 1 adds SQLite with full-text search. Tier 2 brings vector embeddings and anticipatory retrieval. Tier 3 enables an MCP server for mid-session queries, git-tracked projections, and branch-level context isolation.</p><p><strong>Results</strong></p><p>A/B testing across 18 Cortex sessions versus 11 baseline sessions showed measurable gains: an 84% reduction in cold start file re-reading, 80% fewer decision regressions where the AI re-suggested previously rejected approaches, and only 0.2% token overhead for the entire memory system. The system ships with 713 passing tests.</p><p><strong>Implementation Gotchas</strong></p><p>A few hard-won lessons from the build: every <code>.get()</code> call needs a default value, and every JSON parse needs a try/except because Claude Code hooks cannot afford to crash. Content-hash deduplication scopes to session ID to prevent over-deduplication. And the gitleaks GitHub Action requires paid licenses for org accounts, while the CLI stays free&#8212;a distinction that cost some debugging time.</p><p><strong>The Meta-Irony</strong></p><p>The entire project was designed and built using Claude Code&#8212;an AI assistant suffering from the exact problem being solved. Every session boundary during development was a visceral reminder of why this system needed to exist.</p><p><strong>Key Quotes</strong></p><ul><li><p>&#8220;The cruelest aspect: the better the AI performs within a session, the more painful the loss when the session ends. Excellence within a session amplifies the frustration at its boundary.&#8221;</p></li><li><p>&#8220;You can always trace back to &#8216;Why did the system think X?&#8217; &#8212; that&#8217;s the power of event sourcing over CRUD.&#8221;</p></li><li><p>&#8220;Confidence as a first-class field enables downstream flexibility&#8212;briefing sorting, decay functions, user-tunable thresholds.&#8221;</p></li></ul><p><strong>Links</strong></p><ul><li><p>Full article: <a href="https://astgl.com/p/cortex-event-sourced-memory-ai-coding-assistants">https://astgl.com/p/cortex-event-sourced-memory-ai-coding-assistants</a></p></li><li><p>GitHub repository: <a href="https://github.com/As-The-Geek-Learns/cortex">https://github.com/As-The-Geek-Learns/cortex</a></p></li><li><p>As The Geek Learns: <a href="https://astgl.com">https://astgl.com</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Cortex: An Event-Sourced Memory Architecture for AI Coding Assistants]]></title><description><![CDATA[As The Geek Learns | Technical Deep Dive Author: James Cruce Date: February 2026]]></description><link>https://astgl.com/p/cortex-event-sourced-memory-ai-coding-assistants</link><guid isPermaLink="false">https://astgl.com/p/cortex-event-sourced-memory-ai-coding-assistants</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Tue, 17 Feb 2026 17:01:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!lYxh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1e02a7f-bff5-4960-9ca6-1f37b93ca67b_2400x1256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lYxh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1e02a7f-bff5-4960-9ca6-1f37b93ca67b_2400x1256.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lYxh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1e02a7f-bff5-4960-9ca6-1f37b93ca67b_2400x1256.png 424w, https://substackcdn.com/image/fetch/$s_!lYxh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1e02a7f-bff5-4960-9ca6-1f37b93ca67b_2400x1256.png 848w, https://substackcdn.com/image/fetch/$s_!lYxh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1e02a7f-bff5-4960-9ca6-1f37b93ca67b_2400x1256.png 1272w, https://substackcdn.com/image/fetch/$s_!lYxh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1e02a7f-bff5-4960-9ca6-1f37b93ca67b_2400x1256.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lYxh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1e02a7f-bff5-4960-9ca6-1f37b93ca67b_2400x1256.png" width="1456" height="762" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a1e02a7f-bff5-4960-9ca6-1f37b93ca67b_2400x1256.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:762,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1002586,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://astgl.com/i/188071500?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1e02a7f-bff5-4960-9ca6-1f37b93ca67b_2400x1256.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_!lYxh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1e02a7f-bff5-4960-9ca6-1f37b93ca67b_2400x1256.png 424w, https://substackcdn.com/image/fetch/$s_!lYxh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1e02a7f-bff5-4960-9ca6-1f37b93ca67b_2400x1256.png 848w, https://substackcdn.com/image/fetch/$s_!lYxh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1e02a7f-bff5-4960-9ca6-1f37b93ca67b_2400x1256.png 1272w, https://substackcdn.com/image/fetch/$s_!lYxh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1e02a7f-bff5-4960-9ca6-1f37b93ca67b_2400x1256.png 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><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/subscribe?"><span>Subscribe now</span></a></p><p></p><h2>The Problem Every AI Developer Knows Too Well</h2><p>You&#8217;ve been working with Claude Code for two hours. It understands your codebase intimately. It knows you rejected MongoDB because you need zero-config deployment. It remembers the authentication approach you chose and why. It&#8217;s halfway through a five-step refactoring plan.</p><p>Then the session ends.</p><p>The next session begins with total amnesia. Claude suggests MongoDB. It rereads files it already analyzed. It asks questions you answered an hour ago. You spend 30 minutes re-establishing context that evaporated at the session boundary.</p><p><strong>This is the single most painful aspect of working with AI coding assistants today.</strong></p><p>And here&#8217;s what makes it worse: the better the AI performs within a session&#8212;deeper exploration, more nuanced understanding, more careful planning&#8212;the more you lose when that session ends. Good performance within a session just sharpens the pain at its boundary.</p><div><hr></div><h2>What Gets Lost (A Taxonomy of Amnesia)</h2><p>I tracked the problem across dozens of sessions and found five categories of information that get destroyed at every session boundary:</p><h3>Category 1: Architectural Understanding</h3><p>Over the course of a session, the AI maps your codebase&#8212;how components connect, which patterns you use, and where the critical logic sits. Building that map costs real tokens. Then it vanishes.</p><h3>Category 2: Decision History</h3><p>The AI weighs multiple approaches, rejects some with specific reasoning, and picks others. Without that trail, the next session will cheerfully re-suggest the approach you spent ten minutes explaining why you rejected.</p><h3>Category 3: Work State</h3><p>Multi-step plans, half-finished implementations, test results&#8212;all the progress markers for complex work. The next session can&#8217;t pick up where you left off. It has to rediscover the current state from scratch.</p><h3>Category 4: Tool &amp; Environment State</h3><p>Modified files, Git state, environment configuration, and your tooling preferences. All implicitly known during a session. None of it carried forward.</p><h3>Category 5: Conversational Nuance</h3><p>Your preferences, your communication style, the implicit priorities you&#8217;ve established, and the working rapport that took the whole session to build. All ephemeral.</p><h3>The Cascade Effect</h3><p>The information loss doesn&#8217;t stay contained. It cascades:</p><p>1. <strong>Re-exploration waste</strong>: 10-30 minutes spent re-reading files</p><p>2. <strong>Decision regression</strong>: Re-suggesting rejected approaches, eroding trust</p><p>3. <strong>Plan fragmentation</strong>: Multi-step work loses coherence</p><p>4. <strong>Cognitive burden shift</strong>: YOU become the memory system</p><div><hr></div><h2>The Research Journey</h2><p>I spent weeks researching this problem using an AI assistant WITH the context window problem to design a solution FOR the context window problem. The meta-irony was not lost on me.</p><h3>Surveying 15+ Existing Solutions</h3><p>I examined academic architectures (MemGPT, MIRIX, Nemori) and community tools (claude-cortex, memory-mcp, claude-diary). Six distinct design patterns emerged:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_X7E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc253ee3e-b454-48c6-8d0f-a6e86b17fdd7_1800x1600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_X7E!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc253ee3e-b454-48c6-8d0f-a6e86b17fdd7_1800x1600.png 424w, https://substackcdn.com/image/fetch/$s_!_X7E!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc253ee3e-b454-48c6-8d0f-a6e86b17fdd7_1800x1600.png 848w, https://substackcdn.com/image/fetch/$s_!_X7E!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc253ee3e-b454-48c6-8d0f-a6e86b17fdd7_1800x1600.png 1272w, https://substackcdn.com/image/fetch/$s_!_X7E!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc253ee3e-b454-48c6-8d0f-a6e86b17fdd7_1800x1600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_X7E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc253ee3e-b454-48c6-8d0f-a6e86b17fdd7_1800x1600.png" width="1456" height="1294" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c253ee3e-b454-48c6-8d0f-a6e86b17fdd7_1800x1600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1294,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:113270,&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://astgl.com/i/188071500?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc253ee3e-b454-48c6-8d0f-a6e86b17fdd7_1800x1600.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_!_X7E!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc253ee3e-b454-48c6-8d0f-a6e86b17fdd7_1800x1600.png 424w, https://substackcdn.com/image/fetch/$s_!_X7E!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc253ee3e-b454-48c6-8d0f-a6e86b17fdd7_1800x1600.png 848w, https://substackcdn.com/image/fetch/$s_!_X7E!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc253ee3e-b454-48c6-8d0f-a6e86b17fdd7_1800x1600.png 1272w, https://substackcdn.com/image/fetch/$s_!_X7E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc253ee3e-b454-48c6-8d0f-a6e86b17fdd7_1800x1600.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><h3>Eight Candidate Architectures</h3><p>Two rounds of design work produced eight candidates:</p><p>1. <strong>Cognitive Journal&#8212;Human</strong>-readable structured entries</p><p>2. <strong>Memory Palace&#8212;Salience</strong> scoring with decay</p><p>3. <strong>Git-for-Thought&#8212;Branch</strong>-aligned context</p><p>4. <strong>Event Sourcery&#8212;Append</strong>-only event log</p><p>5. <strong>Dual-Mind&#8212;Scribe</strong> + Sage separation</p><p>Then three hybrids combining the best ideas:</p><p>6. <strong>Cortex</strong>&#8212;Event sourcing + projected briefings</p><p>7. <strong>Engram</strong>&#8212;Neural-inspired memory consolidation</p><p>8. <strong>Chronicle</strong>&#8212;Git-native version control</p><h3>Quantitative Scoring</h3><p>I applied an 11-criteria weighted scoring framework across 210 total points. After two rounds of comparison:</p><p><strong>Winner: Cortex (185/210)&#8212;14-point margin</strong> over the runner-up.</p><div><hr></div><h2>The Cortex Architecture</h2><p>Cortex is an <strong>event-sourced memory system</strong> with three key innovations:</p><h3>Innovation 1: Three-Layer Event Extraction</h3><p>Cortex captures context through three independent extraction layers, each watching for different signals:</p><p><strong>Layer 1 (Structural)</strong>: Parses tool call metadata from Claude Code hook payloads. When Claude reads a file, runs a command, or modifies code, the hook captures it. 100% accuracy for its scope&#8212;pure objective data, no interpretation needed.</p><p><strong>Layer 2 (Semantic)</strong>: Pattern-matches Claude&#8217;s response text for decision markers. Look for phrases like &#8220;Decision:&#8221;, &#8220;Rejected:&#8221;, &#8220;Fixed:&#8221;, and &#8220;Learned:&#8221; at line starts. Confidence-scored based on pattern strength.</p><p><strong>Layer 3 (Self-Reporting)</strong>: Claude flags important context via <code>[MEMORY: ...] </code>tags. You tell Claude about this mechanism, and it proactively tags decisions worth remembering. Highest accuracy because it&#8217;s deliberate intent.</p><pre><code># Example: Claude tags a decision
[MEMORY: Using SQLite for storage, zero-config, single file, no external dependencies.]
[MEMORY: Rejected MongoDB, overkill for single-user; no need for scaling.]</code></pre><p>This &#8220;many independent extractors&#8221; pattern shows up across NLP pipelines, content classification, and log analysis for a reason. Each extractor watches for one signal type. They compose through aggregation and dedupe. The alternative&#8212;one monolithic extractor with complex branching&#8212;falls apart as signal types multiply.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fvAr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958f4498-34de-4d38-9bd7-34354cf19d0c_1800x1806.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fvAr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958f4498-34de-4d38-9bd7-34354cf19d0c_1800x1806.png 424w, https://substackcdn.com/image/fetch/$s_!fvAr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958f4498-34de-4d38-9bd7-34354cf19d0c_1800x1806.png 848w, https://substackcdn.com/image/fetch/$s_!fvAr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958f4498-34de-4d38-9bd7-34354cf19d0c_1800x1806.png 1272w, https://substackcdn.com/image/fetch/$s_!fvAr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958f4498-34de-4d38-9bd7-34354cf19d0c_1800x1806.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fvAr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958f4498-34de-4d38-9bd7-34354cf19d0c_1800x1806.png" width="1456" height="1461" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/958f4498-34de-4d38-9bd7-34354cf19d0c_1800x1806.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1461,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:448211,&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://astgl.com/i/188071500?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958f4498-34de-4d38-9bd7-34354cf19d0c_1800x1806.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_!fvAr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958f4498-34de-4d38-9bd7-34354cf19d0c_1800x1806.png 424w, https://substackcdn.com/image/fetch/$s_!fvAr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958f4498-34de-4d38-9bd7-34354cf19d0c_1800x1806.png 848w, https://substackcdn.com/image/fetch/$s_!fvAr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958f4498-34de-4d38-9bd7-34354cf19d0c_1800x1806.png 1272w, https://substackcdn.com/image/fetch/$s_!fvAr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F958f4498-34de-4d38-9bd7-34354cf19d0c_1800x1806.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><div><hr></div><h3>Innovation 2: Projected Briefings</h3><p>Raw event replay would blow the token budget. Instead, Cortex generates <strong>token-budget-aware briefings</strong>:</p><pre><code># Cortex Session Briefing
Generated: 2026-02-14 09:15:00 | Branch: main | Events: 47

## Active Decisions
- **Authentication**: JWT with refresh tokens (rejected session cookies, stateless requirement)
- **Database**: SQLite with WAL mode (rejected PostgreSQL, zero-config priority)

## Current Plan
1. [x] Set up project structure
2. [x] Implement data models
3. [ ] Add API endpoints &#8592; YOU ARE HERE
4. [ ] Write tests
5. [ ] Deploy to staging

## Recent Knowledge
- Config file format changed to TOML (2 sessions ago)
- Tests require PYTHONPATH set (discovered yesterday)</code></pre><p>The briefing fits within a token budget (default 2000 tokens, ~0.1% of context window). Decisions are &#8220;immortal&#8221;&#8212;they never decay out of the briefing. Tactical knowledge fades over sessions.</p><p>This is the core design tension: never lose critical data, but respect resource limits. The resolution&#8212;separate retention from representation. Keep everything in the store. Compress what you surface.</p><h3>Innovation 3: Progressive Tiers</h3><p>Not everyone needs the full stack on day one. Cortex uses progressive tiers&#8212;start simple, and upgrade when you hit the ceiling:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NaoA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e30938e-e10d-4f75-b14d-080a37933344_1800x1600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NaoA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e30938e-e10d-4f75-b14d-080a37933344_1800x1600.png 424w, https://substackcdn.com/image/fetch/$s_!NaoA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e30938e-e10d-4f75-b14d-080a37933344_1800x1600.png 848w, https://substackcdn.com/image/fetch/$s_!NaoA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e30938e-e10d-4f75-b14d-080a37933344_1800x1600.png 1272w, https://substackcdn.com/image/fetch/$s_!NaoA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e30938e-e10d-4f75-b14d-080a37933344_1800x1600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NaoA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e30938e-e10d-4f75-b14d-080a37933344_1800x1600.png" width="1456" height="1294" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0e30938e-e10d-4f75-b14d-080a37933344_1800x1600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1294,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:143425,&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://astgl.com/i/188071500?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e30938e-e10d-4f75-b14d-080a37933344_1800x1600.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_!NaoA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e30938e-e10d-4f75-b14d-080a37933344_1800x1600.png 424w, https://substackcdn.com/image/fetch/$s_!NaoA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e30938e-e10d-4f75-b14d-080a37933344_1800x1600.png 848w, https://substackcdn.com/image/fetch/$s_!NaoA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e30938e-e10d-4f75-b14d-080a37933344_1800x1600.png 1272w, https://substackcdn.com/image/fetch/$s_!NaoA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e30938e-e10d-4f75-b14d-080a37933344_1800x1600.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><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share As The Geek Learns&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share As The Geek Learns</span></a></p><p></p><h2>Implementation Learnings</h2><h3>The Build Backend Gotcha</h3><p><code>setuptools.build_meta</code> is the one true build backend string for setuptools. The original scaffold had <code>setuptools.backends.build_meta</code> which gives a confusing <code>ModuleNotFoundError: No module named &#8216;setuptools.backends&#8217; at install time.</code> This is a common pyproject.toml pitfall.</p><h3>Event Sourcing vs. CRUD</h3><p>The difference between &#8220;store the latest state&#8221; (CRUD) and &#8220;store every fact that happened&#8221; (event sourcing) gets real when you actually build it. The Event model is immutable. All views are projections. You can always trace back to &#8220;why did the system think X?&#8221;&#8212;and that auditability turned out to matter more than I expected.</p><h3>Defensive Defaults Pattern</h3><p>When building systems that must never crash (like Claude Code hooks), every <code>.get() </code>needs a default, every JSON parse needs a try/except, and every function that could fail returns a safe fallback. The pattern is: try: parse &#8594; except: return defaults. Enterprise-grade paranoia for a developer tool, but Claude Code hooks can&#8217;t afford to crash.</p><h3>Content Hash Scoping</h3><p>Deduplication hashes need careful scoping. Hashing just the content would miss that the same text as a &#8220;decision&#8221; vs. &#8220;knowledge&#8221; is semantically different. Hashing the ID would prevent all dedupe. The sweet spot: hash(type + content + session_id).</p><h3>GitHub Action &#8800; Free CLI Tool</h3><p>The gitleaks GitHub Action requires a paid license for org accounts. The gitleaks CLI is free. A lot of security scanning tools follow this model&#8212;they monetize the GitHub integration while the underlying tool stays open-source. Check if you can run the CLI directly before paying for the wrapper.</p><h3>Confidence as Architecture</h3><p>I made confidence a first-class field on every event&#8212;not just a boolean &#8220;is this relevant?&#8221; but a score. That one decision opened up a lot of downstream flexibility. The briefing generator sorts by confidence. The decay function weights it. Users can tune the threshold. A small investment at creation time pays off every time data gets consumed.</p><div><hr></div><h2>A/B Testing Results</h2><p>I ran 18 Cortex-enabled sessions vs. 11 baseline sessions:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5hQY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a6a0f51-0d72-4533-bc65-99dd67a09745_1800x1600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5hQY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a6a0f51-0d72-4533-bc65-99dd67a09745_1800x1600.png 424w, https://substackcdn.com/image/fetch/$s_!5hQY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a6a0f51-0d72-4533-bc65-99dd67a09745_1800x1600.png 848w, https://substackcdn.com/image/fetch/$s_!5hQY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a6a0f51-0d72-4533-bc65-99dd67a09745_1800x1600.png 1272w, https://substackcdn.com/image/fetch/$s_!5hQY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a6a0f51-0d72-4533-bc65-99dd67a09745_1800x1600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5hQY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a6a0f51-0d72-4533-bc65-99dd67a09745_1800x1600.png" width="1456" height="1294" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7a6a0f51-0d72-4533-bc65-99dd67a09745_1800x1600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1294,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:508682,&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://astgl.com/i/188071500?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a6a0f51-0d72-4533-bc65-99dd67a09745_1800x1600.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_!5hQY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a6a0f51-0d72-4533-bc65-99dd67a09745_1800x1600.png 424w, https://substackcdn.com/image/fetch/$s_!5hQY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a6a0f51-0d72-4533-bc65-99dd67a09745_1800x1600.png 848w, https://substackcdn.com/image/fetch/$s_!5hQY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a6a0f51-0d72-4533-bc65-99dd67a09745_1800x1600.png 1272w, https://substackcdn.com/image/fetch/$s_!5hQY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a6a0f51-0d72-4533-bc65-99dd67a09745_1800x1600.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><div><hr></div><h3>Qualitative Feedback</h3><p>Briefings were &#8220;very useful&#8221;&#8212;they consistently contained relevant context.</p><p>Claude remembered decisions and plans <strong>consistently</strong> across sessions.</p><p>No major issues encountered.</p><p><strong>Faster onboarding than expected</strong>&#8212;84% cold start reduction translated to noticeably smoother session starts.</p><p>One thing I&#8217;d recommend: get an outside perspective before you build. I had an external AI stress-test the plan, and it caught a missing measurement strategy I&#8217;d completely overlooked. It forced vague aspirations into concrete mechanisms. Thirty minutes of responding to that critique saved hours of implementation confusion.</p><div><hr></div><h2>The Meta-Irony</h2><p>I built this entire project using an AI assistant that suffers from the exact problem I was solving. Every session note I wrote during development exists because of the limitation I was trying to fix.</p><p>The external evaluator that reviewed my plan? An AI that forgot it did the evaluation by the next session. When I sat down to implement the code, I had to re-explain context that the previous session knew cold.</p><p>That irony hasn&#8217;t resolved itself. But it&#8217;s also the most visceral validation of the problem. If I didn&#8217;t feel this pain daily, I might have underinvested in the fix.</p><div><hr></div><h2>Tier 3: The Latest Features</h2><p>Tier 3 landed recently and adds three capabilities I&#8217;d been wanting since the start:</p><h3>MCP Server (Mid-Session Queries)</h3><p>Claude can now query Cortex memory during a session, not just at session start:</p><blockquote><p><strong>&#8220;What decisions have I made about authentication?&#8221;<br>&#8220;What&#8217;s my current plan?&#8221;<br>&#8220;Search my memory for database configuration issues&#8221;</strong></p></blockquote><p>Five tools expose memory: <em><strong>cortex_search</strong>, <strong>cortex_search_decisions</strong>, <strong>cortex_get_plan</strong>,<strong> cortex_get_recent</strong></em>, and <em><strong>cortex_get_statu</strong></em><strong>s</strong>.</p><h3>Git-Tracked Projections</h3><p>Auto-generated markdown files in .cortex/:</p><pre><code>.cortex/
&#9500;&#9472;&#9472; decisions.md # Active decisions with reasoning
&#9500;&#9472;&#9472; decisions-archive.md # Archived/aged decisions
&#9492;&#9472;&#9472; active-plan.md # Current work plan</code></pre><p>These regenerate at session end and can be committed to Git. Your teammates can see what decisions Claude helped you make and why.</p><h3>Branch Alignment</h3><p>Context gets isolated per Git branch. Switch branches, and Cortex loads the relevant context for that branch. No more cross-contamination between feature work.</p><div><hr></div><h2>Getting Started</h2><pre><code>pip install -e or pip install cortex .
cortex init # Print hook config for Claude Code
cortex status # Show project state
cortex upgrade # Migrate to next tier</code></pre><p>Add the hooks from <code>cortex init </code>to your Claude Code settings. <code>Copy templates/cortex-memory-instructions.md to .claude/rules/ </code>so Claude knows to use <code>[MEMORY: ...] tags</code>.</p><p>That&#8217;s it. Context capture starts automatically.</p><div><hr></div><h2>Key Takeaways</h2><ol><li><p><strong>The context window boundary is the #1 barrier</strong> to using AI assistants for complex, multi-session work.</p></li><li><p><strong>Event sourcing is the right foundation</strong>&#8212;immutable events with projections give you auditability, flexibility, and clean separation of concerns.</p></li><li><p><strong>Three-layer extraction</strong> (structural + semantic + self-reporting) achieves &gt;95% recall for important events without requiring secondary LLM calls.</p></li><li><p><strong>Progressive tiers</strong> mean you start simple and add complexity only when you need it. Tier 0 alone made a noticeable difference.</p></li><li><p><strong>Decisions are immortal</strong>&#8212;the &#8220;why&#8221; behind choices is never lost to temporal decay.</p></li><li><p><strong>Real-world testing validates the design</strong>&#8212;84% cold start reduction, 80% decision regression reduction, 0.2% token overhead.</p></li></ol><div><hr></div><h2>Future Work</h2><p><strong>Tier 4</strong>: Team memory sharing, cross-project knowledge graphs</p><p><strong>Multi-model support</strong>: Extend beyond Claude to other LLM assistants</p><p><strong>IDE integration</strong>: Deeper VS Code / JetBrains integration</p><p><strong>Memory visualization</strong>: UI for exploring and editing the event store</p><div><hr></div><h2>The Bottom Line</h2><p>If you&#8217;ve used AI coding assistants for anything beyond a single session, you know this frustration. Cortex is my answer: an event-sourced memory architecture that captures context automatically, persists it across sessions, and projects it back when you need it&#8212;no model modifications, no manual upkeep.</p><p><strong>The AI assistant finally remembers.</strong></p><div><hr></div><p><em>This article was written with Claude Code, using Cortex to maintain context across the multiple sessions required to complete it. The irony remains unresolved.</em></p><p><strong>713 tests passing. Ships today.</strong></p><div><hr></div><p><em><strong>Please feel free to leave a comment. I will read every one and respond. Looking forward to hearing from you.</strong></em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/cortex-event-sourced-memory-ai-coding-assistants/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/cortex-event-sourced-memory-ai-coding-assistants/comments"><span>Leave a comment</span></a></p><div><hr></div><h2>ASTGL Docs</h2><p><a href="https://github.com/As-The-Geek-Learns/cortex">Cortex GitHub Repository</a>: Full GitHub Repository, Research, Testing, Papers</p><p><a href="https://github.com/As-The-Geek-Learns/cortex/blob/main/docs/research/paper/cortex-research-paper.md">Full Research Paper</a>: Why, How, and What&#8217;s Next for Cortex</p><p><a href="https://github.com/As-The-Geek-Learns/cortex/blob/main/docs/testing/AB-COMPARISON-RESULTS.md">A/B Comparison Results</a>: Real-World Testing of Cortex With and Without</p><p><a href="https://github.com/As-The-Geek-Learns/cortex/releases/tag/v0.3.0">v0.3.0 Release Notes</a>: Current Release Notes for Cortex</p><div><hr></div><h2>References</h2><p><a href="https://code.claude.com/docs/en/memory">Claude Code Memory Docs</a>: Manage Claude&#8217;s Memory</p><p><a href="https://claude.com/blog/context-management">Anthropic Context Management</a>: Context Editing Tool</p><p><a href="https://platform.claude.com/docs/en/build-with-claude/compaction">Claude Code Auto-Compaction</a>: Automatic </p><p><a href="https://code.claude.com/docs/en/hooks-guide">Claude Code Hooks Guide</a>: PreCompact + Session Start</p><p><a href="https://research.memgpt.ai/">MemGPT</a> / <a href="https://docs.letta.com/">Letta Docs</a>: LLM as Operating System Virtual Context Management</p><p><a href="https://mirix.io/">MIRIX</a>: Multi-Type Memory Architecture</p><p><a href="https://arxiv.org/html/2510.18866v1">LightMem</a>: Lightweight Memory Framework</p><p><a href="https://arxiv.org/abs/2405.14831">HippoRag</a>: Neurobiologically Inspired Memory</p><p><a href="https://arxiv.org/abs/2508.03341">Nemori</a>: Self-Organizing Memory</p><p><a href="https://github.com/MemTensor/MemOS">MemOS</a>:  Unified Memory Operating System</p><p><a href="https://dev.to/suede/the-architecture-of-persistent-memory-for-claude-code-17d">memory-mcp</a>: Two-Tier Architecture</p><p><a href="https://pypi.org/project/claude-cortex/">claude-cortex</a>: Brain-like Memory</p><p><a href="https://github.com/doobidoo/mcp-memory-service">mcp-memory-service</a>: Semantic Search</p><p><a href="https://github.com/mkreyman/mcp-memory-keeper">mcp-memory-keeper</a>: Checkpoint System</p><p><a href="https://github.com/donthemannn/claude-continuity">claude-continuity</a>: Auto State Persistence</p><p><a href="https://github.com/thedotmack/claude-mem">claude-mem</a>: Full Capture + Compression</p><p><a href="https://github.com/rlancemartin/claude-diary">claude-diary</a>: Session Journaling</p><p><a href="https://github.com/GMaN1911/claude-cognitive">claude-cognitive</a>: Activation-based File Tracking</p><p><a href="https://aws.amazon.com/blogs/machine-learning/amazon-bedrock-agentcore-memory-building-context-aware-agents/">AWS Bedrock AgentCore Memory</a>: AWS managed service</p><p><a href="https://pieces.app/blog/best-ai-memory-systems">Pieces</a>: Local-First Developer Memory</p><p><a href="https://windsurf.com/">Windsurf</a>: Built-in persistent memory and multi-step agent workflows</p><p><a href="https://www.trae.ai">Trae</a>: Long-context memory and built-in agents</p><p><a href="https://cursor.com/">Cursor</a>: Chat-based agent features (less memory-focused)</p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[The Ironclad Workflow That Prevents Technical Debt]]></title><description><![CDATA[Ironclad Workflow]]></description><link>https://astgl.com/p/ironclad-workflow-prevent-technical-debt</link><guid isPermaLink="false">https://astgl.com/p/ironclad-workflow-prevent-technical-debt</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Wed, 04 Feb 2026 13:02:40 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9BYm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I was about to write my first line of Swift code when I stopped myself.</p><p>Not because I didn&#8217;t know what to write. Because I realized I was about to make a mistake I&#8217;d made dozens of times before: writing code first, configuring quality tools later.</p><p>That path leads to technical debt. Every time.</p><div><hr></div><h2>The Familiar Pattern</h2><p>Here&#8217;s how most projects start:</p><p>Day 1: &#8220;I&#8217;ll just get something working.&#8221; Day 30: 5,000 lines of code. No consistent style. Some files use tabs, others spaces. Import statements scattered randomly. Day 31: &#8220;I should really add a linter.&#8221; Day 32: SwiftLint reports 847 warnings. SwiftFormat wants to change every file. Day 33: &#8220;I&#8217;ll fix those later.&#8221; Day 365: Those 847 warnings are now 2,400. Nobody touches them.</p><p>Sound familiar?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2B0q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2B0q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 424w, https://substackcdn.com/image/fetch/$s_!2B0q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 848w, https://substackcdn.com/image/fetch/$s_!2B0q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 1272w, https://substackcdn.com/image/fetch/$s_!2B0q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2B0q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png" width="828" height="1972" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1972,&quot;width&quot;:828,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:102785,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://astgl.com/i/186785993?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.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_!2B0q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 424w, https://substackcdn.com/image/fetch/$s_!2B0q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 848w, https://substackcdn.com/image/fetch/$s_!2B0q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 1272w, https://substackcdn.com/image/fetch/$s_!2B0q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 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><figcaption class="image-caption">Technical Debt Spiral</figcaption></figure></div><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://astgl.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">As The Geek Learns is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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>The problem isn&#8217;t the linting tools. The problem is when you introduce them. Retrofitting quality enforcement into an existing codebase feels like punishment. Every commit triggers a wall of warnings. Developers start ignoring them. Eventually, someone disables the checks entirely.</p><div><hr></div><h2>Ironclad Workflow: Setup Before Code</h2><p>The solution is simple but counterintuitive: configure all your quality tools before writing any application code.</p><p>I call this the &#8220;Ironclad Workflow&#8221; because once it&#8217;s set up, it&#8217;s nearly impossible to introduce the kind of inconsistency that becomes technical debt.</p><p><strong>Ironclad Workflow Components:</strong> 1. <strong>Git&#8212;Version</strong> control from line one 2. <strong>Linting&#8212;Code</strong> quality rules (SwiftLint for Swift) 3. <strong>Formatting&#8212;Consistent</strong> style (SwiftFormat for Swift) 4. <strong>Pre-commit hooks&#8212;Enforcement</strong> before commits 5. <strong>CI/CD&#8212;Server</strong>-side verification</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9BYm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9BYm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png 424w, https://substackcdn.com/image/fetch/$s_!9BYm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png 848w, https://substackcdn.com/image/fetch/$s_!9BYm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png 1272w, https://substackcdn.com/image/fetch/$s_!9BYm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9BYm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png" width="1456" height="582" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:582,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:61617,&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://astgl.com/i/186785993?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.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_!9BYm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png 424w, https://substackcdn.com/image/fetch/$s_!9BYm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png 848w, https://substackcdn.com/image/fetch/$s_!9BYm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png 1272w, https://substackcdn.com/image/fetch/$s_!9BYm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.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">Ironclad Workflow Order</figcaption></figure></div><p>When these are configured before code exists, every line you write conforms to the rules automatically. There&#8217;s never a &#8220;fix the linting&#8221; task because violations are caught immediately.</p><div><hr></div><h2>Step-by-Step Implementation</h2><p>Here&#8217;s the order that works:</p><p><strong>Step 1: Initialize Git</strong></p><pre><code>git init
git add .gitignore
git commit -m &#8220;chore: initial project setup&#8221;</code></pre><p>Start with version control. Every subsequent setup change gets its own commit. You can always see what changed when.</p><p><strong>Step 2: Configure SwiftLint</strong></p><pre><code># .swiftlint.yml
disabled_rules:
 - line_length # Handled by SwiftFormat
opt_in_rules:
 - empty_count
 - explicit_init
included:
 - Sources
 - Tests</code></pre><p>SwiftLint catches code quality issues: force unwrapping, unused variables, and complex expressions. Configure it before writing code so you learn the rules as you go rather than fighting them later.</p><p><strong>Step 3: Configure SwiftFormat</strong></p><pre><code># .swiftformat
--indent 4
--indentcase true
--trimwhitespace always
--importgrouping alphabetized
--semicolons never</code></pre><p>SwiftFormat handles style: indentation, spacing, and import ordering. Consistent formatting speeds up code reviews because reviewers focus on logic, not style.</p><p><strong>Step 4: Add Pre-Commit Hooks</strong></p><pre><code>#!/bin/sh
# .git/hooks/pre-commit

# Run SwiftFormat
swiftformat --lint .
if [ $? -ne 0 ]; then
 echo &#8220;SwiftFormat failed. Run &#8216;swiftformat .&#8217; to fix.&#8221;
 exit 1
fi

# Run SwiftLint
swiftlint lint --strict
if [ $? -ne 0 ]; then
 echo &#8220;SwiftLint failed. Fix violations before committing.&#8221;
 exit 1
fi</code></pre><p>Pre-commit hooks prevent violations from reaching the repository. You can&#8217;t commit code that fails the checks. This is enforcement, not suggestion.</p><p><strong>Step 5: Configure GitHub Actions</strong></p><pre><code># .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
 lint:
 runs-on: macos-latest
 steps:
 - uses: actions/checkout@v4
 - name: SwiftLint
 run: swiftlint lint --strict
 - name: SwiftFormat
 run: swiftformat --lint .</code></pre><p>CI/CD is the safety net. If someone bypasses pre-commit hooks (using --no-verify), CI catches it. Failed CI blocks merging.</p><div><hr></div><h2>Why This Order Matters</h2><p>The sequence isn&#8217;t arbitrary:</p><p><strong>Git first</strong> because everything else depends on version control. You need commits to track configuration changes.</p><p><strong>Linting before formatting</strong> because linting rules affect code structure, while formatting just affects appearance. Configure the logic rules first.</p><p><strong>Hooks before CI</strong> because local enforcement is faster. You want violations caught in milliseconds on your machine, not minutes later on a build server.</p><p><strong>CI last</strong> because it&#8217;s your backup. CI catches anything that slips through local enforcement.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2PJQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2PJQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png 424w, https://substackcdn.com/image/fetch/$s_!2PJQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png 848w, https://substackcdn.com/image/fetch/$s_!2PJQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png 1272w, https://substackcdn.com/image/fetch/$s_!2PJQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2PJQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png" width="1456" height="1668" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1668,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:164076,&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://astgl.com/i/186785993?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.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_!2PJQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png 424w, https://substackcdn.com/image/fetch/$s_!2PJQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png 848w, https://substackcdn.com/image/fetch/$s_!2PJQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png 1272w, https://substackcdn.com/image/fetch/$s_!2PJQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.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">Enforcement Layers</figcaption></figure></div><p></p><div><hr></div><h2>The Psychological Shift</h2><p>When quality tools exist from the start, they feel like guardrails rather than gatekeepers.</p><p><strong>Retrofit mindset:</strong> &#8220;The linter is blocking my commit.&#8221; <strong>Setup-first mindset:</strong> &#8220;The linter is teaching me the patterns.&#8221;</p><p>This isn&#8217;t just semantics. Developers who learn patterns during development internalize them. Developers who fight patterns during retrofit resent them.</p><p>After a month of Ironclad Workflow, I found myself writing code that passed all checks on the first try. The patterns became muscle memory.</p><div><hr></div><h2>Measuring Success</h2><p>How do you know Ironclad Workflow is working?</p><p><strong>Zero CI failures due to formatting.</strong> If CI ever fails because of a style issue, something&#8217;s wrong with your hooks.</p><p><strong>No &#8220;fix linting&#8221; commits.</strong> Every commit should already be clean. If you&#8217;re batch-fixing violations, your local enforcement isn&#8217;t working.</p><p><strong>Code reviews focus on logic.</strong> Reviewers shouldn&#8217;t comment on formatting or style. Those are automated.</p><p><strong>New developers onboard quickly.</strong> When they run the project for the first time, hooks enforce patterns automatically. No &#8220;read the style guide&#8221; onboarding step.</p><div><hr></div><h2>The Investment</h2><p>Setting up Ironclad Workflow takes about two hours. That's 15 minutes for Git and initial structure, 30 minutes for linting configuration, 30 minutes for formatting configuration, 30 minutes for pre-commit hooks, and 15 minutes for CI/CD.</p><p>Compare that to dozens of hours retrofitting linting later, endless code review cycles about style, the cognitive overhead of inconsistent code, and the frustration of 2,400-warning projects.</p><p>Two hours of setup prevents hundreds of hours of technical debt.</p><div><hr></div><h2>The Lesson</h2><p>Technical debt is easier to prevent than fix.</p><p>Most developers know this intellectually. Few act on it practically. The pull of &#8220;just get something working&#8221; is strong.</p><p>But if you can resist that pull for two hours or just long enough to configure Git, linting, formatting, hooks, and CI, you&#8217;ll never need a &#8220;fix the linting&#8221; sprint again.</p><p><em><strong>Setup before code. Enforcement from line one. Quality by default.</strong></em></p><p>That&#8217;s <strong>Ironclad Workflow.</strong></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/ironclad-workflow-prevent-technical-debt?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/ironclad-workflow-prevent-technical-debt?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div><hr></div><p>James (The Geek) is a systems engineer building apps to fix real-world pain points. </p><p>Drop your story in the comments. I read every one.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/ironclad-workflow-prevent-technical-debt/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/ironclad-workflow-prevent-technical-debt/comments"><span>Leave a comment</span></a></p><p>If you&#8217;re learning to build software while working a day job, <strong>subscribe to As The Geek Learns</strong>. I document the wins, the fails, and the <em><strong>&#8220;I wish someone had told me this earlier&#8221;</strong></em> moments.</p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[The Ironclad Workflow That Prevents Technical Debt]]></title><description><![CDATA[Listen now | Ironclad Workflow]]></description><link>https://astgl.com/p/the-ironclad-workflow-that-prevents</link><guid isPermaLink="false">https://astgl.com/p/the-ironclad-workflow-that-prevents</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Wed, 04 Feb 2026 12:55:18 GMT</pubDate><enclosure url="https://api.substack.com/feed/podcast/186799046/fcb418d2f48f45c1f945fb907b80de07.mp3" length="0" type="audio/mpeg"/><content:encoded><![CDATA[<p>Welcome to the As The Geek Learns podcast. This is episode 5.</p><p>My name is James Cruce and I am the Geek here at As The Geek Learns. No, this is not my voice, but I am glad you are here Listener&#8217;s Note: Due to how painful it is to listen to someone read code, I have removed it from this podcast recording. I am doing you a favor. Please refer to the article for the full code.&#8230;</p><p>We aren&#8217;t sponsored&#8230; Yet, but we do have a new site where you can follow our software development progress. We have a Gumroad store where you can purchase ASTGL apps. Some free and some for dollars and absolutely no software subscriptions. Check it out at <a href="https://astgl.io.">https://astgl.io.</a> Our feature app this week is <strong>Substack Scheduler</strong>: <em>Schedule your Substack Notes. Post at the perfect time, every time. Supports 1 or more substack sites</em>. <strong>No subscription</strong>. ASTGL doesn&#8217;t do subscriptions. If you buy it, you own it. Now onto the episode&#8230;</p><p>I was about to write my first line of Swift code when I stopped myself.</p><p>Not because I didn&#8217;t know what to write. Because I realized I was about to make a mistake I&#8217;d made dozens of times before: writing code first, configuring quality tools later.</p><p>That path leads to technical debt. Every time.</p><div><hr></div><h2>The Familiar Pattern</h2><p>Here&#8217;s how most projects start:</p><p>Day 1: &#8220;I&#8217;ll just get something working.&#8221; Day 30: 5,000 lines of code. No consistent style. Some files use tabs, others spaces. Import statements scattered randomly. Day 31: &#8220;I should really add a linter.&#8221; Day 32: SwiftLint reports 847 warnings. SwiftFormat wants to change every file. Day 33: &#8220;I&#8217;ll fix those later.&#8221; Day 365: Those 847 warnings are now 2,400. Nobody touches them.</p><p>Sound familiar?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2B0q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2B0q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 424w, https://substackcdn.com/image/fetch/$s_!2B0q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 848w, https://substackcdn.com/image/fetch/$s_!2B0q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 1272w, https://substackcdn.com/image/fetch/$s_!2B0q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2B0q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png" width="828" height="1972" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1972,&quot;width&quot;:828,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:102785,&quot;alt&quot;:&quot;&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://astgl.com/i/186785993?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!2B0q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 424w, https://substackcdn.com/image/fetch/$s_!2B0q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 848w, https://substackcdn.com/image/fetch/$s_!2B0q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.png 1272w, https://substackcdn.com/image/fetch/$s_!2B0q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd83b165-65b4-4077-8cc7-0d15ebda699c_828x1972.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">Technical Debt Spiral</figcaption></figure></div><div><hr></div><p>As The Geek Learns is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p><p>The problem isn&#8217;t the linting tools. The problem is when you introduce them. Retrofitting quality enforcement into an existing codebase feels like punishment. Every commit triggers a wall of warnings. Developers start ignoring them. Eventually, someone disables the checks entirely.</p><div><hr></div><h2>Ironclad Workflow: Setup Before Code</h2><p>The solution is simple but counterintuitive: configure all your quality tools before writing any application code.</p><p>I call this the &#8220;Ironclad Workflow&#8221; because once it&#8217;s set up, it&#8217;s nearly impossible to introduce the kind of inconsistency that becomes technical debt.</p><p><strong>Ironclad Workflow Components:</strong> 1. <strong>Git&#8212;Version</strong> control from line one 2. <strong>Linting&#8212;Code</strong> quality rules (SwiftLint for Swift) 3. <strong>Formatting&#8212;Consistent</strong> style (SwiftFormat for Swift) 4. <strong>Pre-commit hooks&#8212;Enforcement</strong> before commits 5. <strong>CI/CD&#8212;Server</strong>-side verification</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9BYm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9BYm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png 424w, https://substackcdn.com/image/fetch/$s_!9BYm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png 848w, https://substackcdn.com/image/fetch/$s_!9BYm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png 1272w, https://substackcdn.com/image/fetch/$s_!9BYm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9BYm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png" width="1456" height="582" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:582,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:61617,&quot;alt&quot;:&quot;&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://astgl.com/i/186785993?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!9BYm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png 424w, https://substackcdn.com/image/fetch/$s_!9BYm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png 848w, https://substackcdn.com/image/fetch/$s_!9BYm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.png 1272w, https://substackcdn.com/image/fetch/$s_!9BYm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05054d49-413f-4ecc-b7a2-27ec526f5cda_1536x614.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">Ironclad Workflow Order</figcaption></figure></div><p>When these are configured before code exists, every line you write conforms to the rules automatically. There&#8217;s never a &#8220;fix the linting&#8221; task because violations are caught immediately.</p><div><hr></div><h2>Step-by-Step Implementation</h2><p>Here&#8217;s the order that works:</p><p><strong>Step 1: Initialize Git</strong></p><pre><code><code>git init
git add .gitignore
git commit -m &#8220;chore: initial project setup&#8221;</code></code></pre><p>Start with version control. Every subsequent setup change gets its own commit. You can always see what changed when.</p><p><strong>Step 2: Configure SwiftLint</strong></p><pre><code><code># .swiftlint.yml
disabled_rules:
 - line_length # Handled by SwiftFormat
opt_in_rules:
 - empty_count
 - explicit_init
included:
 - Sources
 - Tests</code></code></pre><p>SwiftLint catches code quality issues: force unwrapping, unused variables, and complex expressions. Configure it before writing code so you learn the rules as you go rather than fighting them later.</p><p><strong>Step 3: Configure SwiftFormat</strong></p><pre><code><code># .swiftformat
--indent 4
--indentcase true
--trimwhitespace always
--importgrouping alphabetized
--semicolons never</code></code></pre><p>SwiftFormat handles style: indentation, spacing, and import ordering. Consistent formatting speeds up code reviews because reviewers focus on logic, not style.</p><p><strong>Step 4: Add Pre-Commit Hooks</strong></p><pre><code><code>#!/bin/sh
# .git/hooks/pre-commit

# Run SwiftFormat
swiftformat --lint .
if [ $? -ne 0 ]; then
 echo &#8220;SwiftFormat failed. Run &#8216;swiftformat .&#8217; to fix.&#8221;
 exit 1
fi

# Run SwiftLint
swiftlint lint --strict
if [ $? -ne 0 ]; then
 echo &#8220;SwiftLint failed. Fix violations before committing.&#8221;
 exit 1
fi</code></code></pre><p>Pre-commit hooks prevent violations from reaching the repository. You can&#8217;t commit code that fails the checks. This is enforcement, not suggestion.</p><p><strong>Step 5: Configure GitHub Actions</strong></p><pre><code><code># .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
 lint:
 runs-on: macos-latest
 steps:
 - uses: actions/checkout@v4
 - name: SwiftLint
 run: swiftlint lint --strict
 - name: SwiftFormat
 run: swiftformat --lint .</code></code></pre><p>CI/CD is the safety net. If someone bypasses pre-commit hooks (using --no-verify), CI catches it. Failed CI blocks merging.</p><div><hr></div><h2>Why This Order Matters</h2><p>The sequence isn&#8217;t arbitrary:</p><p><strong>Git first</strong> because everything else depends on version control. You need commits to track configuration changes.</p><p><strong>Linting before formatting</strong> because linting rules affect code structure, while formatting just affects appearance. Configure the logic rules first.</p><p><strong>Hooks before CI</strong> because local enforcement is faster. You want violations caught in milliseconds on your machine, not minutes later on a build server.</p><p><strong>CI last</strong> because it&#8217;s your backup. CI catches anything that slips through local enforcement.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2PJQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2PJQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png 424w, https://substackcdn.com/image/fetch/$s_!2PJQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png 848w, https://substackcdn.com/image/fetch/$s_!2PJQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png 1272w, https://substackcdn.com/image/fetch/$s_!2PJQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2PJQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png" width="1456" height="1668" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1668,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:164076,&quot;alt&quot;:&quot;&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://astgl.com/i/186785993?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!2PJQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png 424w, https://substackcdn.com/image/fetch/$s_!2PJQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png 848w, https://substackcdn.com/image/fetch/$s_!2PJQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.png 1272w, https://substackcdn.com/image/fetch/$s_!2PJQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c0b87bb-d0d1-435a-85fa-95704efb9e52_1536x1760.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">Enforcement Layers</figcaption></figure></div><div><hr></div><h2>The Psychological Shift</h2><p>When quality tools exist from the start, they feel like guardrails rather than gatekeepers.</p><p><strong>Retrofit mindset:</strong> &#8220;The linter is blocking my commit.&#8221; <strong>Setup-first mindset:</strong> &#8220;The linter is teaching me the patterns.&#8221;</p><p>This isn&#8217;t just semantics. Developers who learn patterns during development internalize them. Developers who fight patterns during retrofit resent them.</p><p>After a month of Ironclad Workflow, I found myself writing code that passed all checks on the first try. The patterns became muscle memory.</p><div><hr></div><h2>Measuring Success</h2><p>How do you know Ironclad Workflow is working?</p><p><strong>Zero CI failures due to formatting.</strong> If CI ever fails because of a style issue, something&#8217;s wrong with your hooks.</p><p><strong>No &#8220;fix linting&#8221; commits.</strong> Every commit should already be clean. If you&#8217;re batch-fixing violations, your local enforcement isn&#8217;t working.</p><p><strong>Code reviews focus on logic.</strong> Reviewers shouldn&#8217;t comment on formatting or style. Those are automated.</p><p><strong>New developers onboard quickly.</strong> When they run the project for the first time, hooks enforce patterns automatically. No &#8220;read the style guide&#8221; onboarding step.</p><div><hr></div><h2>The Investment</h2><p>Setting up Ironclad Workflow takes about two hours. That&#8217;s 15 minutes for Git and initial structure, 30 minutes for linting configuration, 30 minutes for formatting configuration, 30 minutes for pre-commit hooks, and 15 minutes for CI/CD.</p><p>Compare that to dozens of hours retrofitting linting later, endless code review cycles about style, the cognitive overhead of inconsistent code, and the frustration of 2,400-warning projects.</p><p>Two hours of setup prevents hundreds of hours of technical debt.</p><div><hr></div><h2>The Lesson</h2><p>Technical debt is easier to prevent than fix.</p><p>Most developers know this intellectually. Few act on it practically. The pull of &#8220;just get something working&#8221; is strong.</p><p>But if you can resist that pull for two hours or just long enough to configure Git, linting, formatting, hooks, and CI, you&#8217;ll never need a &#8220;fix the linting&#8221; sprint again.</p><p><em><strong>Setup before code. Enforcement from line one. Quality by default.</strong></em></p><p>That&#8217;s <strong>Ironclad Workflow.</strong></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/the-ironclad-workflow-that-prevents?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://astgl.com/p/the-ironclad-workflow-that-prevents?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div><hr></div><p>James (The Geek) is a systems engineer building apps to fix real-world pain points. </p><p>Drop your story in the comments. I read every one.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/the-ironclad-workflow-that-prevents/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://astgl.com/p/the-ironclad-workflow-that-prevents/comments"><span>Leave a comment</span></a></p><p></p><p>James (The Geek) is a systems engineer building apps to fix real-world pain points&#8230;</p><p>Drop your comments; we love them, everyone. I read every one.</p><p>If you&#8217;re learning to build software while working a day job, <strong><a href="https://podcasts.apple.com/us/podcast/as-the-geek-learns/id1859284856">subscribe to the As The Geek Learns</a></strong><a href="https://podcasts.apple.com/us/podcast/as-the-geek-learns/id1859284856"> podcast</a>. I document the wins, the fails, and the <strong>&#8220;I wish someone had told me this earlier&#8221;</strong> moments.</p><p>Until next time&#8212;stay curious, keep scripting, and remember: every expert was once a beginner who just refused to quit. I&#8217;m James, and this has been As The Geek Learns.</p><p>One last thing: if you&#8217;re getting value from the show, drop me a rating on <a href="https://podcasts.apple.com/us/podcast/as-the-geek-learns/id1859284856">Apple Podcasts</a>. Five stars keeps the lights on, but honestly? Even a review that says, &#8216;This guy talks about PowerShell too much,&#8216; helps the algorithm. I&#8217;ll take it.</p>]]></content:encoded></item><item><title><![CDATA[I Got Tired of Paying for Substack Notes Schedulers, So I Built My Own]]></title><description><![CDATA[I learned how to build a Substack Notes scheduler by reverse engineering their undocumented API. Covers architecture decisions, TOS compliance, and tech stack.]]></description><link>https://astgl.com/p/substack-notes-scheduler-i-built-my-own-part-1</link><guid isPermaLink="false">https://astgl.com/p/substack-notes-scheduler-i-built-my-own-part-1</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Tue, 13 Jan 2026 17:03:14 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!XFSB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff32e2438-45aa-4346-a833-54d08cfe74dc_1920x1080.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>The Problem That Started It All</h2><p>If you publish on Substack, you&#8217;ve probably discovered their dirty little secret: you can schedule newsletter posts, but you <em>can&#8217;t</em> schedule Notes. Substack Notes, their Twitter/X competitor baked into the platform, requires you to be there, fingers on keyboard, posting at exactly the right moment.</p><p>The market noticed this gap fast. Chrome extensions like Writestack and Finn Tropy&#8217;s Scheduler popped up, charging $25-50 for scheduling functionality. But here&#8217;s what drove me up the wall: <strong>every single one requires your browser to stay open 24/7</strong>.</p><p>Why? Because they&#8217;re not calling APIs at all. They inject JavaScript into Substack&#8217;s web page, fill in the note composer programmatically, and literally click &#8216;Post&#8217; for you at the scheduled time. Close your laptop lid, and your scheduled posts vanish into the ether.</p><p>For someone who&#8217;s spent 25 years building enterprise automation, this felt like an affront to my professional sensibilities. There had to be a better way.</p><h2>Understanding the Existing Landscape</h2><p>Before writing any code, I needed to understand what I was dealing with.</p><h3><strong>How Browser Extensions Actually Work</strong></h3><p>The existing Chrome extensions all follow the same pattern: they inject JavaScript into the Substack Notes page, use your active browser session for authentication, store scheduled notes in Chrome&#8217;s LocalStorage, and then programmatically fill the composer and click &#8216;Post&#8217; when the time comes.</p><p>The browser has to stay open because they&#8217;re automating the UI, not calling APIs directly. That&#8217;s a fundamental architectural limitation, not a feature gap they forgot to address.</p><h3><strong>The Substack &#8220;API&#8221; Discovery</strong></h3><p>Substack has no official public API. That&#8217;s intentional. They want to control the platform experience. But their web application has to communicate with servers somehow, and that &#8216;somehow&#8217; is a set of internal REST endpoints.</p><p>The key insight came from digging into network traffic: these internal endpoints can be called directly if you have the right session cookie (connect.sid). This cookie gets issued when you log in and typically lasts weeks or months.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://astgl.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">As The Geek Learns is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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><div><hr></div><p></p><h2>The Terms of Service Question</h2><p>Before investing serious time, I needed to understand the legal landscape. Digging through Substack&#8217;s TOS and existing extension documentation surfaced one critical insight:</p><div class="pullquote"><p><em>&#8220;Substack terms and conditions prevent any system that would require you to disclose your credentials, so no external servers or services can be used for sending Notes.&#8221;</em></p></div><p>This has major implications. Personal tools you build for yourself? Completely fine, since you&#8217;re using your own credentials. CLI tools that users run locally? Fine, because credentials stay on their machine. Desktop apps? Also fine, with credentials stored locally. A SaaS service where you handle user credentials on your servers? That&#8217;s where you run into problems.</p><p>This shaped the entire product direction: a desktop app with local credential storage hits the sweet spot for commercial viability without TOS issues.</p><h2>Architecture Decision: Python CLI as Foundation</h2><p>Given my automation background and the goal of eventually building a commercial product, I went with Python for the core logic.</p><h3><strong>Why Python?</strong></h3><p>The syntax feels familiar coming from PowerShell. The HTTP libraries are excellent, and requests is perfect for this kind of work. It runs anywhere: Mac, Linux, Windows, Raspberry Pi, and cloud VMs. Quick iteration with no compile step. And the packaging story is solid. The same code can become a CLI tool, then a desktop app.</p><h3><strong>The Evolution Path I Mapped Out</strong></h3><p>Phase 1 would be a personal script, just Python and cron for my own dogfooding. No TOS risk. Phase 2, a packaged CLI tool I could sell as a one-time purchase for $20-50. Low TOS risk. Phase 3, a Tauri-wrapped desktop app, either one-time or subscription. Still low risk. Phase 4 would be a full SaaS service with cloud and browser automation and a subscription model but higher TOS risk.</p><p>The decision became clear: build a desktop app where users keep their own credentials locally. This respects the TOS while providing a professional user experience.</p><h2>The Desktop Framework Decision: Tauri vs. Electron</h2><p>For wrapping a web UI into a desktop app, two main contenders exist: <a href="https://tauri.app/">Tauri </a>and <a href="https://www.electronjs.org/">Electron</a>.</p><p>Tauri produces binaries around 3-10 MB with lower memory usage since it uses the system webview. Faster startup, <a href="https://rust-lang.org/">Rust</a> backend. Version 2.0 is stable. Electron produces 150-200 MB binaries with higher memory usage because it bundles Chromium. Slower startup, <a href="https://nodejs.org/en">Node.js</a> backend, but extremely mature.</p><p><strong>Decision: Tauri 2.0</strong></p><p>Size matters for distribution. 5&nbsp;MB versus 150&nbsp;MB affects download perception. And &#8216;lightweight &amp; fast&#8217; becomes a selling point for a utility app. The Rust backend would auto-start the Python scheduling daemon as a sidecar process.<br><br></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/substack-notes-scheduler-i-built-my-own-part-1?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/substack-notes-scheduler-i-built-my-own-part-1?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><h2>API Reverse Engineering: The Technical Foundation</h2><p>Before building anything, I needed to prove the core posting logic would actually work.</p><h3><strong>Step 1: Cookie Extraction</strong></h3><p>Getting the session cookie requires a one-time manual step. Open Chrome DevTools (Cmd+Option+I), go to your Substack publication&#8217;s Notes page, switch to the Network tab, post a test note manually, then find the POST request and copy the cookie string.</p><h3><strong>Step 2: Endpoint Discovery</strong></h3><p>Based on online research, I expected the Notes endpoint to be:</p><pre><code> POST /api/v1/notes.</code></pre><p>It isn&#8217;t.</p><p>After network trace analysis, I discovered Notes are actually posted via:</p><pre><code>POST https://{publication-domain}/api/v1/comment/feed</code></pre><p>The naming makes sense once you understand Substack&#8217;s architecture: Notes evolved from their commenting system. They literally are &#8216;comments on your own feed.&#8217;</p><h3><strong>Step 3: Custom Domain Discovery</strong></h3><p>If you have a custom domain (like resistandrise.blue or astgl.com), API calls go to that domain, not substack.com. Critical for multi-publication support.</p><h3><strong>Step 4: Payload Structure</strong></h3><p>Substack uses ProseMirror for content. The JSON structure wraps your text in a doc with a schema version, containing paragraphs with text nodes. There&#8217;s also a replyMinimumRole field set to &#8216;everyone.&#8217;</p><h2>The Product Vision</h2><p>With research complete, I had a clear picture.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XFSB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff32e2438-45aa-4346-a833-54d08cfe74dc_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XFSB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff32e2438-45aa-4346-a833-54d08cfe74dc_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!XFSB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff32e2438-45aa-4346-a833-54d08cfe74dc_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!XFSB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff32e2438-45aa-4346-a833-54d08cfe74dc_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!XFSB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff32e2438-45aa-4346-a833-54d08cfe74dc_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XFSB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff32e2438-45aa-4346-a833-54d08cfe74dc_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f32e2438-45aa-4346-a833-54d08cfe74dc_1920x1080.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;:100431,&quot;alt&quot;:&quot;Blueprint-style architecture diagram showing the Substack Scheduler desktop app design. Left side shows crossed-out browser-dependent Chrome extensions labeled \&quot;Existing Solutions.\&quot; Center shows the new Tauri 2.0 desktop app containing React UI, Python backend, and Scheduler daemon with local credential and queue storage. Right side shows connection to Substack's undocumented REST API endpoint. Bottom lists four key benefits: no browser required, local credentials, reverse engineered API, and multi-publication 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://astgl.com/i/184356446?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff32e2438-45aa-4346-a833-54d08cfe74dc_1920x1080.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Blueprint-style architecture diagram showing the Substack Scheduler desktop app design. Left side shows crossed-out browser-dependent Chrome extensions labeled &quot;Existing Solutions.&quot; Center shows the new Tauri 2.0 desktop app containing React UI, Python backend, and Scheduler daemon with local credential and queue storage. Right side shows connection to Substack's undocumented REST API endpoint. Bottom lists four key benefits: no browser required, local credentials, reverse engineered API, and multi-publication support." title="Blueprint-style architecture diagram showing the Substack Scheduler desktop app design. Left side shows crossed-out browser-dependent Chrome extensions labeled &quot;Existing Solutions.&quot; Center shows the new Tauri 2.0 desktop app containing React UI, Python backend, and Scheduler daemon with local credential and queue storage. Right side shows connection to Substack's undocumented REST API endpoint. Bottom lists four key benefits: no browser required, local credentials, reverse engineered API, and multi-publication support." srcset="https://substackcdn.com/image/fetch/$s_!XFSB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff32e2438-45aa-4346-a833-54d08cfe74dc_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!XFSB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff32e2438-45aa-4346-a833-54d08cfe74dc_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!XFSB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff32e2438-45aa-4346-a833-54d08cfe74dc_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!XFSB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff32e2438-45aa-4346-a833-54d08cfe74dc_1920x1080.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">Substack Scheduler System Architecture</figcaption></figure></div><h3><strong>Target User: </strong></h3><p>Substack creators who want to schedule Notes without browser dependencies</p><h3><strong>Core Value Proposition:</strong></h3><p>Schedule Notes days, weeks, or months in advance. Runs in the background with no browser required. Works offline and posts when you&#8217;re back online. Multi-account support for creators managing multiple publications.</p><h3><strong>Pricing Model (One-time purchase, tiered):</strong></h3><p><a href="https://astgl.gumroad.com/l/substack-scheduler">Personal at $29 for 1 account. Creator at $49 for 3 accounts. Agency at $99 for unlimited accounts.</a></p><h3><strong>Technology Stack:</strong></h3><p><a href="https://www.python.org/">Python</a> backend using <a href="https://fastapi.tiangolo.com/">FastAPI</a> for the API and scheduling daemon. React frontend for the web-based UI. Tauri desktop wrapper to package everything together. <a href="https://astgl.gumroad.com/l/substack-scheduler">Gumroad </a>for payment and licensing.</p><h2>What&#8217;s Next</h2><p>With the research complete and architecture planned, <a href="http://substack-notes-scheduler-I-built-my-own-part-2">Part 2 </a>covers actually building the thing, from proof-of-concept CLI to polished desktop application.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/substack-notes-scheduler-i-built-my-own-part-1?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading As The Geek Learns! This post is public, so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/substack-notes-scheduler-i-built-my-own-part-1?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/substack-notes-scheduler-i-built-my-own-part-1?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><p></p><p><em><strong>Have you used an AI to help you research and build an app? I&#8217;d love to hear your experiences. Leave comments or questions. I will answer every one. &#8212; The Geek</strong></em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/substack-notes-scheduler-i-built-my-own-part-1/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/substack-notes-scheduler-i-built-my-own-part-1/comments"><span>Leave a comment</span></a></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Database Schema Design Mistake That Broke My App]]></title><description><![CDATA[How real-world usage revealed a fundamental flaw in my database design]]></description><link>https://astgl.com/p/database-schema-design-mistake-that</link><guid isPermaLink="false">https://astgl.com/p/database-schema-design-mistake-that</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Fri, 09 Jan 2026 18:39:50 GMT</pubDate><enclosure url="https://api.substack.com/feed/podcast/183955624/67a222f62f6ae948dca06e1f6bc898d2.mp3" length="0" type="audio/mpeg"/><content:encoded><![CDATA[<blockquote><p><strong>TL;DR: </strong>My Johnny Decimal index app had a three-level <strong>database schema</strong> when the system requires four levels. I&#8217;d conflated folder containers with the files inside them&#8212;a fundamental <strong>data model</strong> flaw. One week of dogfooding caught what months of planning completely missed. Key lessons: use your own software early, match your data model to your mental model, and refactor before you accumulate data you&#8217;ll need to migrate.</p></blockquote><div><hr></div><p>I&#8217;d been using JDex, my Johnny Decimal index application, for about a week when a fundamental <strong>database schema design</strong> flaw became impossible to ignore.</p><p>The app worked beautifully. I could create areas and categories. I could track items with their XX.XX identifiers. The search was fast, the UI was clean, and I was feeling pretty good about what I&#8217;d built.</p><p>Then I tried to organize real files.</p><p>Somehow I had folders and the files inside them sitting at the same level in my database. My <strong>data model</strong> had three levels when Johnny Decimal requires four.</p><p>Here&#8217;s how one week of <strong>dogfooding</strong> caught what months of planning completely missed and the four lessons I&#8217;m carrying into every future project.</p><h2>The Problem I Didn&#8217;t See Coming</h2><h3>How Johnny Decimal Hierarchy Actually Works</h3><p>Johnny Decimal (<a href="https://johnnydecimal.com">johnnydecimal.com</a>) is a system for organizing files and information. It has a clear four-level hierarchy:</p><p>Area (00-09)</p><p>&#9492;&#9472;&#9472; Category (00, 01, 02...)</p><p>&#9492;&#9472;&#9472; ID Folder (00.01, 00.02...)</p><p>&#9492;&#9472;&#9472; Actual Files</p><p>Level What It Is Number Format Example</p><p>1 Area 00 - 09 00-09 System</p><p>2 Category XX 00 Index</p><p>3 Folder XX.XX 00.01 JDex Database</p><p>4 Item XX.XX.XX 00.01.01 Main DB File</p><p>My database had three levels: areas, categories, and... items.</p><p><em>Where do the ID folders go?</em></p><h3>Why My Three-Level Database Schema Failed</h3><p>I&#8217;d conflated two fundamentally different things:</p><p><strong>Folder containers: </strong>the XX.XX numbered folders that hold files</p><p><strong>Actual files: </strong>the contents inside those folders</p><p>In my original <strong>schema design</strong>, &#8220;00.01 JDex Database&#8221; (a folder) and the SQLite file inside it (an item) existed at the same level in the database. That&#8217;s like saying a filing cabinet drawer and the documents inside it are the same thing.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nF3k!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nF3k!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png 424w, https://substackcdn.com/image/fetch/$s_!nF3k!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png 848w, https://substackcdn.com/image/fetch/$s_!nF3k!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png 1272w, https://substackcdn.com/image/fetch/$s_!nF3k!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nF3k!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png" width="800" height="516" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:516,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:167360,&quot;alt&quot;:&quot;&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://astgl.com/i/183589971?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!nF3k!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png 424w, https://substackcdn.com/image/fetch/$s_!nF3k!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png 848w, https://substackcdn.com/image/fetch/$s_!nF3k!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png 1272w, https://substackcdn.com/image/fetch/$s_!nF3k!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.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><h3>Why Database Schema Mismatches Break Core Functionality</h3><p>This wasn&#8217;t just aesthetically wrong. The three-level <strong>data model</strong> broke features I needed:</p><p><strong>I couldn&#8217;t track what was inside a folder. </strong>The whole point of Johnny Decimal is knowing &#8220;everything about taxes lives in 12.04.&#8221; But my schema had no way to list what was actually <em>in</em> 12.04. The folder and its contents were peers, not parent and child.</p><p><strong>Folder-level properties were impossible. </strong>What if everything in a folder should be marked as sensitive? With my original design, I&#8217;d have to set that flag on every individual item. There was no way to say, &#8220;This container and everything in it shares this property.&#8221;</p><p><strong>The numbering didn&#8217;t work. </strong>Johnny Decimal items should be XX.XX.XX&#8212;three segments. Mine only went to XX.XX because I&#8217;d eliminated an entire level.</p><p>When your <strong>data model</strong> doesn&#8217;t match the mental model of the system you&#8217;re building, you&#8217;ll keep running into walls. The database fights you instead of helping you.</p><h2>The Fix: Adding a Fourth Level</h2><p>The solution was straightforward conceptually but required rethinking the entire <strong>database schema</strong>: the old items table became folders. A new items table was created for the actual tracked objects inside those folders.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pDTn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pDTn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png 424w, https://substackcdn.com/image/fetch/$s_!pDTn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png 848w, https://substackcdn.com/image/fetch/$s_!pDTn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png 1272w, https://substackcdn.com/image/fetch/$s_!pDTn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pDTn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png" width="1456" height="964" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:964,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:524140,&quot;alt&quot;:&quot;Entity relationship diagram of the refactored JDex database schema. Shows four tables: Areas (id, area_number, name), Categories (id, category_number, area_id, name), Folders (id, folder_number, category_id, name, sensitivity), and Items (id, item_number, folder_id, name, sensitivity with 'inherit' option). Foreign key relationships are indicated by connecting lines between tables.&quot;,&quot;title&quot;:&quot;Entity relationship diagram of the refactored JDex database schema. Shows four tables: Areas (id, area_number, name), Categories (id, category_number, area_id, name), Folders (id, folder_number, category_id, name, sensitivity), and Items (id, item_number, folder_id, name, sensitivity with 'inherit' option). Foreign key relationships are indicated by connecting lines between tables.&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://astgl.com/i/183589971?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Entity relationship diagram of the refactored JDex database schema. Shows four tables: Areas (id, area_number, name), Categories (id, category_number, area_id, name), Folders (id, folder_number, category_id, name, sensitivity), and Items (id, item_number, folder_id, name, sensitivity with 'inherit' option). Foreign key relationships are indicated by connecting lines between tables." title="Entity relationship diagram of the refactored JDex database schema. Shows four tables: Areas (id, area_number, name), Categories (id, category_number, area_id, name), Folders (id, folder_number, category_id, name, sensitivity), and Items (id, item_number, folder_id, name, sensitivity with 'inherit' option). Foreign key relationships are indicated by connecting lines between tables." srcset="https://substackcdn.com/image/fetch/$s_!pDTn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png 424w, https://substackcdn.com/image/fetch/$s_!pDTn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png 848w, https://substackcdn.com/image/fetch/$s_!pDTn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png 1272w, https://substackcdn.com/image/fetch/$s_!pDTn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.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><div><hr></div><h3>The Refactored Database Schema</h3><p>Here&#8217;s what the corrected structure looks like:</p><p>-- Folders (Level 3) - XX.XX format containers</p><p>CREATE TABLE folders (</p><p>id INTEGER PRIMARY KEY,</p><p>folder_number TEXT UNIQUE, -- &#8220;22.05&#8221;</p><p>category_id INTEGER,</p><p>name TEXT,</p><p>sensitivity TEXT DEFAULT &#8216;standard&#8217;,</p><p>created_at TIMESTAMP,</p><p>updated_at TIMESTAMP,</p><p>FOREIGN KEY (category_id) REFERENCES categories(id)</p><p>);</p><p>-- Items (Level 4) - XX.XX.XX format objects</p><p>CREATE TABLE items (</p><p>id INTEGER PRIMARY KEY,</p><p>item_number TEXT UNIQUE, -- &#8220;22.05.03&#8221;</p><p>folder_id INTEGER,</p><p>name TEXT,</p><p>sensitivity TEXT DEFAULT &#8216;inherit&#8217;, -- Can inherit from folder</p><p>file_path TEXT,</p><p>notes TEXT,</p><p>created_at TIMESTAMP,</p><p>updated_at TIMESTAMP,</p><p>FOREIGN KEY (folder_id) REFERENCES folders(id)</p><p>);</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ejbe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ejbe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png 424w, https://substackcdn.com/image/fetch/$s_!Ejbe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png 848w, https://substackcdn.com/image/fetch/$s_!Ejbe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png 1272w, https://substackcdn.com/image/fetch/$s_!Ejbe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ejbe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png" width="1456" height="837" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:837,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:157023,&quot;alt&quot;:&quot;&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://astgl.com/i/183589971?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Ejbe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png 424w, https://substackcdn.com/image/fetch/$s_!Ejbe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png 848w, https://substackcdn.com/image/fetch/$s_!Ejbe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png 1272w, https://substackcdn.com/image/fetch/$s_!Ejbe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.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>The inherit option for item sensitivity was a bonus insight that emerged from the refactor. Most items should just use their folder&#8217;s sensitivity level. Only exceptions need explicit overrides. That&#8217;s not something I could have implemented with the old three-level schema.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!omAa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!omAa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png 424w, https://substackcdn.com/image/fetch/$s_!omAa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png 848w, https://substackcdn.com/image/fetch/$s_!omAa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png 1272w, https://substackcdn.com/image/fetch/$s_!omAa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!omAa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png" width="1324" height="1432" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1432,&quot;width&quot;:1324,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:205933,&quot;alt&quot;:&quot;&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://astgl.com/i/183589971?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!omAa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png 424w, https://substackcdn.com/image/fetch/$s_!omAa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png 848w, https://substackcdn.com/image/fetch/$s_!omAa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png 1272w, https://substackcdn.com/image/fetch/$s_!omAa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.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><div><hr></div><h2>Four Lessons from This Database Design Mistake</h2><h3>Use Your Own Software (Dogfooding)</h3><p>The <strong>schema</strong> flaw was invisible in design documents and code reviews. It only appeared when I tried to organize real files with real data.</p><p>A week of daily use caught what months of planning missed.</p><p>There&#8217;s no substitute for using your own software to accomplish real tasks. You&#8217;ll discover conceptual mismatches that no amount of testing or review will reveal. If you&#8217;re building something, use it yourself as soon as it&#8217;s minimally functional.</p><h3>Match Data Models to Mental Models</h3><p>I knew Johnny Decimal had four levels. I could draw them on a whiteboard. Yet somehow my database had three.</p><p>That mismatch was always going to cause problems&#8212;I just hadn&#8217;t encountered them yet. When you&#8217;re modeling a real-world system, count the levels. Write them down. Then count the levels in your database. Do they match?</p><p>Containers and contents are different things, even if they both have names and locations. This seems like common sense now, but when I was building the original schema, I simply didn&#8217;t see the issue.</p><h3>Database Schema Changes Are Easier Early</h3><p>This <strong>refactor</strong> touched every database function and most UI components. It was significant work.</p><p>If I&#8217;d caught this flaw after six months of data entry, migration would have been painful. I&#8217;d have needed to write migration scripts, test them against production data, handle edge cases, and pray nothing broke.</p><p>Catching it in week one meant a clean restart. I dumped all the data because it was easier than trying to preserve and migrate it. That&#8217;s a luxury you only have early in a project.</p><h3>Keep Your AI Context Updated</h3><p>I&#8217;ve been bouncing ideas off Claude to see what might work and what definitely won&#8217;t. It&#8217;s been helpful for thinking through problems and catching issues.</p><p>But here&#8217;s what I didn&#8217;t anticipate: my Claude Project configuration had the old three-level schema baked in. After the refactor, I had to update those instructions so the AI understood the new structure and why I changed it.</p><p>The configuration is only as good as the context it contains. If your tools are working from outdated assumptions, they&#8217;ll give you outdated guidance. This applies to AI assistants, documentation, onboarding materials, and anything that encodes how your system works.</p><p>I should have just let Claude help build the schema in the first place. But I was trying to learn as I went, and that&#8217;s the tradeoff. I&#8217;m not a coder by trade, just a systems engineer who likes to automate as much as possible.</p><div><hr></div><p>&#128236; <em>Learning to code while working full-time? You&#8217;re not alone. Subscribe to As The Geek Learns for weekly lessons from the trenches&#8212;the wins, the fails, and the &#8220;I wish someone had told me&#8221; moments.</em></p><div><hr></div><h2>Database Design Checklist for Hierarchical Data Projects</h2><p>If you&#8217;re building something that models a hierarchy, run through this before you write code:</p><p><strong>Count the levels in the real-world system. </strong>Write them down. Then count the levels in your database schema. Do they match exactly?</p><p><strong>Distinguish containers from contents. </strong>Are there things that hold other things? Those need separate tables or entities, not just a &#8220;type&#8221; field.</p><p><strong>Define the numbering scheme. </strong>If your system has identifiers like XX.XX.XX, your schema needs to support generating and validating that format at each level.</p><p><strong>Identify inheritable properties. </strong>What attributes should cascade from parent to child? Design for that explicitly (like the sensitivity: inherit option I added).</p><p><strong>Plan for schema evolution. </strong>Your first model probably won&#8217;t be your last. How hard will it be to add a level later? To split a table? Design with migration in mind.</p><div><hr></div><h2>What&#8217;s Next for JDex</h2><p>JDex is better now. The four-level <strong>hierarchical database</strong> design matches how Johnny Decimal actually works, and I can finally track what&#8217;s inside a folder.</p><p>The most important bugs aren&#8217;t always in your code; they&#8217;re in your assumptions. The <strong>schema</strong> looked right. The code worked. But the underlying model was wrong, and no amount of polish would have fixed that.</p><p><em>One week of real use revealed what months of planning couldn&#8217;t.</em></p><p><em>James is a systems engineer building JDex as a learning project while documenting the journey. Follow along at <a href="https://astgl.com">As The Geek Learns</a> for more lessons from the trenches of learning to code.</em></p><p><strong>Have you discovered a fundamental flaw hiding in your project&#8217;s design? How did you find it?</strong> Drop your story in the comments. I read every one.</p><p>If you&#8217;re learning to build software while working a day job, <strong>subscribe to As The Geek Learns</strong>. I document the wins, the fails, and the <em><strong>&#8220;I wish someone had told me this earlier&#8221;</strong></em> moments.</p>]]></content:encoded></item><item><title><![CDATA[Database Schema Design Mistake That Broke My App]]></title><description><![CDATA[How real-world usage revealed a fundamental flaw in my database design]]></description><link>https://astgl.com/p/database-schema-design-mistake</link><guid isPermaLink="false">https://astgl.com/p/database-schema-design-mistake</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Fri, 09 Jan 2026 18:38:32 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!nF3k!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p><strong>TL;DR: </strong>My Johnny Decimal index app had a three-level <strong>database schema</strong> when the system requires four levels. I&#8217;d conflated folder containers with the files inside them&#8212;a fundamental <strong>data model</strong> flaw. One week of dogfooding caught what months of planning completely missed. Key lessons: use your own software early, match your data model to your mental model, and refactor before you accumulate data you&#8217;ll need to migrate.</p></blockquote><div><hr></div><p>I&#8217;d been using JDex, my Johnny Decimal index application, for about a week when a fundamental <strong>database schema design</strong> flaw became impossible to ignore.</p><p>The app worked beautifully. I could create areas and categories. I could track items with their XX.XX identifiers. The search was fast, the UI was clean, and I was feeling pretty good about what I&#8217;d built.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://astgl.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">As The Geek Learns is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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>Then I tried to organize real files.</p><p>Somehow I had folders and the files inside them sitting at the same level in my database. My <strong>data model</strong> had three levels when Johnny Decimal requires four.</p><p>Here&#8217;s how one week of <strong>dogfooding</strong> caught what months of planning completely missed and the four lessons I&#8217;m carrying into every future project.</p><h2>The Problem I Didn&#8217;t See Coming</h2><h3>How Johnny Decimal Hierarchy Actually Works</h3><p>Johnny Decimal (<a href="https://johnnydecimal.com">johnnydecimal.com</a>) is a system for organizing files and information. It has a clear four-level hierarchy:</p><p>Area (00-09)</p><p>&#9492;&#9472;&#9472; Category (00, 01, 02...)</p><p>&#9492;&#9472;&#9472; ID Folder (00.01, 00.02...)</p><p>&#9492;&#9472;&#9472; Actual Files</p><p>Level What It Is Number Format Example</p><p>1 Area 00 - 09 00-09 System</p><p>2 Category XX 00 Index</p><p>3 Folder XX.XX 00.01 JDex Database</p><p>4 Item XX.XX.XX 00.01.01 Main DB File</p><p>My database had three levels: areas, categories, and... items.</p><p><em>Where do the ID folders go?</em></p><h3>Why My Three-Level Database Schema Failed</h3><p>I&#8217;d conflated two fundamentally different things:</p><p><strong>Folder containers: </strong>the XX.XX numbered folders that hold files</p><p><strong>Actual files: </strong>the contents inside those folders</p><p>In my original <strong>schema design</strong>, &#8220;00.01 JDex Database&#8221; (a folder) and the SQLite file inside it (an item) existed at the same level in the database. That&#8217;s like saying a filing cabinet drawer and the documents inside it are the same thing.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nF3k!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nF3k!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png 424w, https://substackcdn.com/image/fetch/$s_!nF3k!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png 848w, https://substackcdn.com/image/fetch/$s_!nF3k!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png 1272w, https://substackcdn.com/image/fetch/$s_!nF3k!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nF3k!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png" width="800" height="516" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:516,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:167360,&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://astgl.com/i/183589971?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.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_!nF3k!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png 424w, https://substackcdn.com/image/fetch/$s_!nF3k!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png 848w, https://substackcdn.com/image/fetch/$s_!nF3k!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.png 1272w, https://substackcdn.com/image/fetch/$s_!nF3k!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a2e2e6e-527c-474a-bd46-0956652de743_800x516.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><h3>Why Database Schema Mismatches Break Core Functionality</h3><p>This wasn&#8217;t just aesthetically wrong. The three-level <strong>data model</strong> broke features I needed:</p><p><strong>I couldn&#8217;t track what was inside a folder. </strong>The whole point of Johnny Decimal is knowing &#8220;everything about taxes lives in 12.04.&#8221; But my schema had no way to list what was actually <em>in</em> 12.04. The folder and its contents were peers, not parent and child.</p><p><strong>Folder-level properties were impossible. </strong>What if everything in a folder should be marked as sensitive? With my original design, I&#8217;d have to set that flag on every individual item. There was no way to say, &#8220;This container and everything in it shares this property.&#8221;</p><p><strong>The numbering didn&#8217;t work. </strong>Johnny Decimal items should be XX.XX.XX&#8212;three segments. Mine only went to XX.XX because I&#8217;d eliminated an entire level.</p><p>When your <strong>data model</strong> doesn&#8217;t match the mental model of the system you&#8217;re building, you&#8217;ll keep running into walls. The database fights you instead of helping you.</p><h2>The Fix: Adding a Fourth Level</h2><p>The solution was straightforward conceptually but required rethinking the entire <strong>database schema</strong>: the old items table became folders. A new items table was created for the actual tracked objects inside those folders.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pDTn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pDTn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png 424w, https://substackcdn.com/image/fetch/$s_!pDTn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png 848w, https://substackcdn.com/image/fetch/$s_!pDTn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png 1272w, https://substackcdn.com/image/fetch/$s_!pDTn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pDTn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png" width="1456" height="964" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:964,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:524140,&quot;alt&quot;:&quot;Entity relationship diagram of the refactored JDex database schema. Shows four tables: Areas (id, area_number, name), Categories (id, category_number, area_id, name), Folders (id, folder_number, category_id, name, sensitivity), and Items (id, item_number, folder_id, name, sensitivity with 'inherit' option). Foreign key relationships are indicated by connecting lines between 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://astgl.com/i/183589971?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Entity relationship diagram of the refactored JDex database schema. Shows four tables: Areas (id, area_number, name), Categories (id, category_number, area_id, name), Folders (id, folder_number, category_id, name, sensitivity), and Items (id, item_number, folder_id, name, sensitivity with 'inherit' option). Foreign key relationships are indicated by connecting lines between tables." title="Entity relationship diagram of the refactored JDex database schema. Shows four tables: Areas (id, area_number, name), Categories (id, category_number, area_id, name), Folders (id, folder_number, category_id, name, sensitivity), and Items (id, item_number, folder_id, name, sensitivity with 'inherit' option). Foreign key relationships are indicated by connecting lines between tables." srcset="https://substackcdn.com/image/fetch/$s_!pDTn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png 424w, https://substackcdn.com/image/fetch/$s_!pDTn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png 848w, https://substackcdn.com/image/fetch/$s_!pDTn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.png 1272w, https://substackcdn.com/image/fetch/$s_!pDTn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b79a0a-1bbc-4ebc-af5d-7228b3afc200_1834x1214.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><div><hr></div><h3>The Refactored Database Schema</h3><p>Here&#8217;s what the corrected structure looks like:</p><p>-- Folders (Level 3) - XX.XX format containers</p><p>CREATE TABLE folders (</p><p>id INTEGER PRIMARY KEY,</p><p>folder_number TEXT UNIQUE, -- &#8220;22.05&#8221;</p><p>category_id INTEGER,</p><p>name TEXT,</p><p>sensitivity TEXT DEFAULT &#8216;standard&#8217;,</p><p>created_at TIMESTAMP,</p><p>updated_at TIMESTAMP,</p><p>FOREIGN KEY (category_id) REFERENCES categories(id)</p><p>);</p><p>-- Items (Level 4) - XX.XX.XX format objects</p><p>CREATE TABLE items (</p><p>id INTEGER PRIMARY KEY,</p><p>item_number TEXT UNIQUE, -- &#8220;22.05.03&#8221;</p><p>folder_id INTEGER,</p><p>name TEXT,</p><p>sensitivity TEXT DEFAULT &#8216;inherit&#8217;, -- Can inherit from folder</p><p>file_path TEXT,</p><p>notes TEXT,</p><p>created_at TIMESTAMP,</p><p>updated_at TIMESTAMP,</p><p>FOREIGN KEY (folder_id) REFERENCES folders(id)</p><p>);</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ejbe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ejbe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png 424w, https://substackcdn.com/image/fetch/$s_!Ejbe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png 848w, https://substackcdn.com/image/fetch/$s_!Ejbe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png 1272w, https://substackcdn.com/image/fetch/$s_!Ejbe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ejbe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png" width="1456" height="837" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:837,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:157023,&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://astgl.com/i/183589971?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.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_!Ejbe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png 424w, https://substackcdn.com/image/fetch/$s_!Ejbe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png 848w, https://substackcdn.com/image/fetch/$s_!Ejbe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.png 1272w, https://substackcdn.com/image/fetch/$s_!Ejbe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68ae5d2c-bfbd-48cc-9d58-a8512c1e7965_1994x1146.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>The inherit option for item sensitivity was a bonus insight that emerged from the refactor. Most items should just use their folder&#8217;s sensitivity level. Only exceptions need explicit overrides. That&#8217;s not something I could have implemented with the old three-level schema.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!omAa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!omAa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png 424w, https://substackcdn.com/image/fetch/$s_!omAa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png 848w, https://substackcdn.com/image/fetch/$s_!omAa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png 1272w, https://substackcdn.com/image/fetch/$s_!omAa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!omAa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png" width="1324" height="1432" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1432,&quot;width&quot;:1324,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:205933,&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://astgl.com/i/183589971?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.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_!omAa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png 424w, https://substackcdn.com/image/fetch/$s_!omAa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png 848w, https://substackcdn.com/image/fetch/$s_!omAa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.png 1272w, https://substackcdn.com/image/fetch/$s_!omAa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c6f0b23-10d2-4202-a867-329182ea0837_1324x1432.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><div><hr></div><h2>Four Lessons from This Database Design Mistake</h2><h3>Use Your Own Software (Dogfooding)</h3><p>The <strong>schema</strong> flaw was invisible in design documents and code reviews. It only appeared when I tried to organize real files with real data.</p><p>A week of daily use caught what months of planning missed.</p><p>There&#8217;s no substitute for using your own software to accomplish real tasks. You&#8217;ll discover conceptual mismatches that no amount of testing or review will reveal. If you&#8217;re building something, use it yourself as soon as it&#8217;s minimally functional.</p><h3>Match Data Models to Mental Models</h3><p>I knew Johnny Decimal had four levels. I could draw them on a whiteboard. Yet somehow my database had three.</p><p>That mismatch was always going to cause problems&#8212;I just hadn&#8217;t encountered them yet. When you&#8217;re modeling a real-world system, count the levels. Write them down. Then count the levels in your database. Do they match?</p><p>Containers and contents are different things, even if they both have names and locations. This seems like common sense now, but when I was building the original schema, I simply didn&#8217;t see the issue.</p><h3>Database Schema Changes Are Easier Early</h3><p>This <strong>refactor</strong> touched every database function and most UI components. It was significant work.</p><p>If I&#8217;d caught this flaw after six months of data entry, migration would have been painful. I&#8217;d have needed to write migration scripts, test them against production data, handle edge cases, and pray nothing broke.</p><p>Catching it in week one meant a clean restart. I dumped all the data because it was easier than trying to preserve and migrate it. That&#8217;s a luxury you only have early in a project.</p><h3>Keep Your AI Context Updated</h3><p>I&#8217;ve been bouncing ideas off Claude to see what might work and what definitely won&#8217;t. It&#8217;s been helpful for thinking through problems and catching issues.</p><p>But here&#8217;s what I didn&#8217;t anticipate: my Claude Project configuration had the old three-level schema baked in. After the refactor, I had to update those instructions so the AI understood the new structure and why I changed it.</p><p>The configuration is only as good as the context it contains. If your tools are working from outdated assumptions, they&#8217;ll give you outdated guidance. This applies to AI assistants, documentation, onboarding materials, and anything that encodes how your system works.</p><p>I should have just let Claude help build the schema in the first place. But I was trying to learn as I went, and that&#8217;s the tradeoff. I&#8217;m not a coder by trade, just a systems engineer who likes to automate as much as possible.</p><div><hr></div><p>&#128236; <em>Learning to code while working full-time? You&#8217;re not alone. Subscribe to As The Geek Learns for weekly lessons from the trenches&#8212;the wins, the fails, and the &#8220;I wish someone had told me&#8221; moments.</em></p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/database-schema-design-mistake?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading As The Geek Learns! This post is public, so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/database-schema-design-mistake?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/database-schema-design-mistake?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><h2>Database Design Checklist for Hierarchical Data Projects</h2><p>If you&#8217;re building something that models a hierarchy, run through this before you write code:</p><p><strong>Count the levels in the real-world system. </strong>Write them down. Then count the levels in your database schema. Do they match exactly?</p><p><strong>Distinguish containers from contents. </strong>Are there things that hold other things? Those need separate tables or entities, not just a &#8220;type&#8221; field.</p><p><strong>Define the numbering scheme. </strong>If your system has identifiers like XX.XX.XX, your schema needs to support generating and validating that format at each level.</p><p><strong>Identify inheritable properties. </strong>What attributes should cascade from parent to child? Design for that explicitly (like the sensitivity: inherit option I added).</p><p><strong>Plan for schema evolution. </strong>Your first model probably won&#8217;t be your last. How hard will it be to add a level later? To split a table? Design with migration in mind.</p><div><hr></div><h2>What&#8217;s Next for JDex</h2><p>JDex is better now. The four-level <strong>hierarchical database</strong> design matches how Johnny Decimal actually works, and I can finally track what&#8217;s inside a folder.</p><p>The most important bugs aren&#8217;t always in your code; they&#8217;re in your assumptions. The <strong>schema</strong> looked right. The code worked. But the underlying model was wrong, and no amount of polish would have fixed that.</p><p><em>One week of real use revealed what months of planning couldn&#8217;t.</em></p><p><em>James is a systems engineer building JDex as a learning project while documenting the journey. Follow along at <a href="https://astgl.com">As The Geek Learns</a> for more lessons from the trenches of learning to code.</em></p><p><strong>Have you discovered a fundamental flaw hiding in your project&#8217;s design? How did you find it?</strong> Drop your story in the comments. I read every one.</p><p>If you&#8217;re learning to build software while working a day job, <strong>subscribe to As The Geek Learns</strong>. I document the wins, the fails, and the <em><strong>&#8220;I wish someone had told me this earlier&#8221;</strong></em> moments. </p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/database-schema-design-mistake/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/database-schema-design-mistake/comments"><span>Leave a comment</span></a></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[How I Built JDex with Claude AI—A Systems Engineer's Honest Take]]></title><description><![CDATA[A systems engineer shares his experience building JDex, a Johnny Decimal index app, using Claude AI&#8212;including what AI collaboration actually looks like in practice.]]></description><link>https://astgl.com/p/how-i-built-jdex-with-claude-aia</link><guid isPermaLink="false">https://astgl.com/p/how-i-built-jdex-with-claude-aia</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Sat, 20 Dec 2025 18:00:25 GMT</pubDate><enclosure url="https://api.substack.com/feed/podcast/182183163/d66fa970b66f9e9ef57e538796df2faf.mp3" length="0" type="audio/mpeg"/><content:encoded><![CDATA[<p></p>]]></content:encoded></item><item><title><![CDATA[How I Built JDex with Claude AI—A Systems Engineer's Honest Take]]></title><description><![CDATA[A systems engineer shares his experience building JDex, a Johnny Decimal index app, using Claude AI&#8212;including what AI collaboration actually looks like in practice.]]></description><link>https://astgl.com/p/building-jdex-with-claude-ai</link><guid isPermaLink="false">https://astgl.com/p/building-jdex-with-claude-ai</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Sat, 20 Dec 2025 18:00:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Adkw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c670c1-df17-4ba9-acda-2f1ba942f9b5_640x413.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In <a href="https://astgl.com/p/i-had-files-scattered-across-4-clouds">Part 1 of this series</a>, I shared my file organization disaster: years of digital chaos spread across four cloud services and two laptops. I discovered the <a href="https://johnnydecimal.com/">Johnny Decimal system</a>, a methodology that finally made sense, but I needed a tool to actually implement it across my sprawling reality.</p><p>So I decided to build one. But I&#8217;m a systems engineer, not a web developer. I can write PowerShell scripts in my sleep, but building a proper web application? Different skill set entirely.</p><p>This is where AI-assisted app development got interesting.</p><div><hr></div><h2>From AI Answers to AI Collaboration</h2><p>I&#8217;d been using <a href="https://claude.ai">Claude</a>, Anthropic&#8217;s AI assistant, for various work tasks. Technical documentation. Script debugging. Research. But I hadn&#8217;t explored what it would be like to build something <em>with</em> AI rather than just getting answers from it.</p><p>I started describing what I wanted: a web-based index for managing Johnny Decimal systems across multiple storage locations. Something accessible from any device. Something that would help me track not just where files <em>should</em> go, but where they currently <em>are</em> as I work through the migration.</p><p>What followed was genuinely collaborative. Not &#8220;AI writes code, human copies and pastes,&#8221; but an actual back-and-forth of designing, building, testing, and refining.</p><p>I&#8217;d describe a feature. Claude would propose an implementation. I&#8217;d test it, find edge cases, and explain what wasn&#8217;t working. We&#8217;d iterate. Sometimes I&#8217;d have a half-formed idea, and Claude would help me think through implications before writing any code.</p><p>I consider Claude a partner in this process. That&#8217;s not hype. It&#8217;s the most accurate description of how the work actually happened.</p><div><hr></div><h2>What JDex Does: A Johnny Decimal Index App</h2><p>JDex is the Johnny Decimal index application that emerged from this collaboration. At its core, it lets you:</p><p><strong>Define your structure</strong>: Create areas and categories that match how you think about your information.</p><p><strong>Track locations</strong>: Note where files actually live, including which cloud service, which device, and which folder path.</p><p><strong>Manage the index</strong>: The heart of Johnny Decimal is the index, a master reference of what exists and where it belongs.</p><p><strong>Search and navigate</strong>: Find any ID quickly, see what&#8217;s in each category, and understand your system at a glance.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Adkw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c670c1-df17-4ba9-acda-2f1ba942f9b5_640x413.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Adkw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c670c1-df17-4ba9-acda-2f1ba942f9b5_640x413.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Adkw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c670c1-df17-4ba9-acda-2f1ba942f9b5_640x413.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Adkw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c670c1-df17-4ba9-acda-2f1ba942f9b5_640x413.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Adkw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c670c1-df17-4ba9-acda-2f1ba942f9b5_640x413.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Adkw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c670c1-df17-4ba9-acda-2f1ba942f9b5_640x413.jpeg" width="640" height="413" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/21c670c1-df17-4ba9-acda-2f1ba942f9b5_640x413.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:413,&quot;width&quot;:640,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:128830,&quot;alt&quot;:&quot;JDex application interface displaying Johnny Decimal areas and categories with location tracking&quot;,&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://astgl.com/i/182171372?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c670c1-df17-4ba9-acda-2f1ba942f9b5_640x413.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="JDex application interface displaying Johnny Decimal areas and categories with location tracking" title="JDex application interface displaying Johnny Decimal areas and categories with location tracking" srcset="https://substackcdn.com/image/fetch/$s_!Adkw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c670c1-df17-4ba9-acda-2f1ba942f9b5_640x413.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Adkw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c670c1-df17-4ba9-acda-2f1ba942f9b5_640x413.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Adkw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c670c1-df17-4ba9-acda-2f1ba942f9b5_640x413.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Adkw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c670c1-df17-4ba9-acda-2f1ba942f9b5_640x413.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><figcaption class="image-caption">JDex App</figcaption></figure></div><p>The working application matters, but what I learned about building with AI matters more.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://astgl.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 As The Geek Learns! 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><div><hr></div><h2>4 Lessons from Building an App with Claude AI</h2><h4>1. AI collaboration is a skill</h4><p>Like working with a human colleague, you get better at it. I learned to describe problems more clearly, break complex features into manageable pieces, and provide useful feedback when something wasn&#8217;t quite right. The quality of what Claude produced directly correlated with the quality of context I provided.</p><h4>2. The human brings the context</h4><p>Claude doesn&#8217;t know my file organization history, my workflow, or my pain points. I had to bring that context to every conversation. The AI could suggest solutions, but only I could evaluate whether they fit my actual life. Domain expertise isn&#8217;t replaced&#8212;it&#8217;s leveraged.</p><h4>3. It&#8217;s genuinely faster</h4><p>Things that would have taken weeks of learning web development frameworks happened in hours. Not because AI did all the work, but because it accelerated the parts I didn&#8217;t know while I focused on the parts I did. For a systems engineer exploring app development, this changes what&#8217;s possible.</p><h4>4. The result feels like mine</h4><p>This surprised me most. JDex isn&#8217;t something Claude built that I&#8217;m using. It emerged from hundreds of small decisions I made, issues I identified, and features I prioritized. The AI was a capable partner, but the vision and direction were always mine.</p><div><hr></div><p>This article is also available in podcast format: <a href="https://astgl.com/podcast">The ASTGL Podcast</a></p><div><hr></div><h2>What's Next for JDex</h2><p>JDex is functional but not finished. I&#8217;m using it daily as I implement my own Johnny Decimal system, and real-world usage keeps surfacing improvements.</p><p>I&#8217;ll be sharing more here on As The Geek Learns:</p><ul><li><p><strong>How I structured my Johnny Decimal system (decisions and tradeoffs)</strong></p></li><li><p><strong>Technical deep dives on JDex features</strong></p></li><li><p><strong>Lessons from migrating years of digital clutter</strong></p></li><li><p><strong>Honest assessments of where AI collaboration helps and where it doesn&#8217;t</strong></p></li></ul><p>We&#8217;re at an interesting moment with AI tools. Underneath the hype, there&#8217;s something real: people with ideas and domain expertise can build things that previously required skills they didn&#8217;t have.</p><p>I&#8217;m not a developer. But I had a clear problem, years of experience with organizational systems, and access to an AI that could help translate vision into working code. That&#8217;s a new kind of leverage worth exploring seriously.</p><p><strong>JDex is my first real experiment in that space. It won&#8217;t be my last.</strong></p><div><hr></div><h3>FAQ</h3><p><strong>What is JDex?</strong> JDex is a web-based application for managing Johnny Decimal file organization systems. It lets you define your category structure, track where files are stored across multiple locations, and maintain a searchable index of your entire system.</p><p><strong>Do I need coding experience to use JDex?</strong> No. JDex is a user-facing application, not a coding tool. You interact with it through a web interface to manage your Johnny Decimal system.</p><p><strong>Can I build an app with Claude AI if I&#8217;m not a developer?</strong> Yes, with cautions. You need enough technical literacy to test, debug, and direct the process. My background as a systems engineer helped. I understood logic and structure even without web development experience. Complete beginners would face a steeper learning curve.</p><p><strong>Is JDex available to use?</strong> JDex is currently in development. Follow As The Geek Learns for updates on availability.</p><div><hr></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/building-jdex-with-claude-ai?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading As The Geek Learns! This post is public, so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/building-jdex-with-claude-ai?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/building-jdex-with-claude-ai?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><p><em>James is a systems engineer, writer, and builder. He publishes <strong>As The Geek Learns </strong>at <a href="https://astgl.com">astgl.com</a> and writes about surveillance technology and democratic resistance at <a href="https://resistandrise.blue">Resist and Rise</a>.</em></p><div><hr></div><p><strong>Series: Building JDex</strong></p><ul><li><p>Part 1: <a href="https://astgl.com/p/i-had-files-scattered-across-4-clouds">The File Organization Problem</a></p></li><li><p>Part 2: How I Built JDex with Claude AI (You are here)</p></li><li><p>Part 3: Coming soon</p></li></ul><div><hr></div><p><strong>Have you built anything with AI assistance? What was the collaboration actually like? Let me know in the comments.</strong></p><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/building-jdex-with-claude-ai/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/building-jdex-with-claude-ai/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[I Had Files Scattered Across 4 Clouds. So I Built an App with AI to Fix It]]></title><description><![CDATA[Listen now | Part 1: How the Johnny Decimal system finally made sense of my digital chaos. A systems engineer with 25 years managing enterprise infrastructure finally tackled personal file chaos using the Johnny Decimal system. Part 1 of a series on organizing files across iCloud, Dropbox, OneDrive, and more.]]></description><link>https://astgl.com/p/i-had-files-scattered-across-4-clouds-4e2</link><guid isPermaLink="false">https://astgl.com/p/i-had-files-scattered-across-4-clouds-4e2</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Thu, 11 Dec 2025 16:00:44 GMT</pubDate><enclosure url="https://api.substack.com/feed/podcast/181169273/e38e2aad2e441ebcdc72c124d82f391d.mp3" length="0" type="audio/mpeg"/><content:encoded><![CDATA[<p>Here&#8217;s something embarrassing. I&#8217;m a systems engineer. Twenty-five years managing enterprise infrastructure. And until recently? My personal file system was a complete mess.</p><p>Files everywhere. iCloud, Dropbox, OneDrive, ProtonDrive. Two laptops. External drives with names like &#8220;Backup_OLD_FINAL_v2.&#8221; Folders buried 8 levels deep with names I made up in 2003 and haven&#8217;t thought about since.</p><p>At work, I help manage around 5,500 virtual desktops running on VMware ESXi. Before that, I spent years on the server side; I&#8217;ve probably built and retired over 15,000 virtual servers throughout my career. I can script my way through complex VMware migrations without breaking a sweat. But ask me to find that PDF of my home insurance policy? Yeah. Good luck with that.</p><p>If this sounds familiar, keep reading.</p><h2>The Problem Nobody Talks About</h2><p>Digital clutter sneaks up on you. It builds quietly, one &#8220;I&#8217;ll organize this later&#8221; at a time. Then suddenly you&#8217;re staring at a search bar, trying to remember which of four cloud services might have the document you need.</p><p>Productivity gurus love to say, &#8220;Just pick a system.&#8221; Easy for them. They&#8217;re usually not dealing with:</p><ul><li><p>Work files that absolutely must stay separate from personal stuff</p></li><li><p>Sensitive documents that need encrypted storage</p></li><li><p>Collaborative projects scattered across different platforms</p></li><li><p>Years of accumulated digital life that doesn&#8217;t fit neatly anywhere</p></li></ul><p>I tried everything. Color-coded folders. Strict naming conventions. Applied the &#8220;inbox zero&#8221; mindset to my files. Each approach worked for maybe three weeks. Then chaos won. It always does.</p><p>That&#8217;s when I stumbled onto Johnny Decimal, on Reddit, of course.</p><h2>A System That Actually Made Sense</h2><p>Johnny Decimal is a file organization method created by Johnny Noble. The idea is simple: you get a maximum of 10 areas (your broad categories), and each area can hold a maximum of 10 categories (more specific groupings). Every single file gets a unique ID based on where it belongs.</p><p>Instead of wading through <code>/Documents/Work/Projects/2024/Client_ABC/Reports/Final/</code>, you end up with something like <code>32.14 Client ABC Q3 Report</code>.</p><p>The constraints are the whole point. When you limit yourself to 10 areas and 10 categories per area, you actually have to think about how you organize things. Nothing goes deeper than two levels. Every file has a home. You can tell someone &#8220;it&#8217;s in 32.14&#8221; and they know exactly where to look.</p><p>I read through Johnny&#8217;s documentation, and something just clicked. This wasn&#8217;t some organizational B.S. that would fade in six months. It&#8217;s a real framework for thinking about how information connects to other information.</p><p>But I had a problem.</p><h2>The Gap Between Theory and My Reality</h2><p>Johnny Decimal works great when you&#8217;re starting fresh with one file system. I was looking at four cloud services, two machines, and years of accumulated chaos that all needed to be cataloged, cross-referenced, and migrated.</p><p>I needed more than a methodology. I needed a tool.</p><p>Here&#8217;s what I was looking for:</p><ul><li><p>A central index to track where everything lives across all my storage platforms</p></li><li><p>A way to assign and manage Johnny Decimal IDs without going crazy</p></li><li><p>Something that could grow with me as I slowly brought order to the mess</p></li></ul><p>I searched for existing solutions. Some solid tools exist, but nothing quite fit my multi-platform, sprawling-digital-life situation.</p><p>So I built it myself. With an unusual partner helping me along the way.</p><p><em>Next time: What it actually looks like to build an app with AI as your collaborator&#8212;the process, the tool I created, and what I learned about this new kind of partnership.</em></p><p><strong>Have you tried Johnny Decimal? Struggled with multi-cloud chaos? I&#8217;d love to hear your experiences in the comments.</strong></p><p>Until next time&#8212;stay curious, keep scripting, and remember: every expert was once a beginner who just refused to quit. I&#8217;m James, and this has been <strong><a href="https://astgl.com/">As The Geek Learns</a></strong>.</p><p><strong>One last thing: if you&#8217;re getting value from the show, drop me a rating on <a href="https://podcasts.apple.com/us/podcast/as-the-geek-learns/id1859284856">Apple Podcasts</a>. Five stars keeps the lights on, but honestly? Even a review that says &#8216;this guy talks about PowerShell too much&#8217; helps the algorithm. I&#8217;ll take it.</strong></p>]]></content:encoded></item><item><title><![CDATA[I Had Files Scattered Across 4 Clouds. So I Built an App with AI to Fix It]]></title><description><![CDATA[Part 1: Why the Johnny Decimal file organization system finally clicked. A systems engineer with 25 years managing enterprise infrastructure finally tackled personal file chaos using the Johnny Decimal file system. Part 1 of a series on organizing files across iCloud, Dropbox, OneDrive, and more.]]></description><link>https://astgl.com/p/i-had-files-scattered-across-4-clouds</link><guid isPermaLink="false">https://astgl.com/p/i-had-files-scattered-across-4-clouds</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Thu, 11 Dec 2025 13:00:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!nt55!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9836e88-6b06-466e-99d4-c02df98f5b28_800x1200.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://astgl.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 As The Geek Learns! 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>Here&#8217;s something embarrassing. I&#8217;m a systems engineer. Twenty-five years managing enterprise infrastructure. And until recently? My personal file system was a complete mess.</p><p>Files everywhere. iCloud, Dropbox, OneDrive, ProtonDrive. Two laptops. External drives with names like &#8220;Backup_OLD_FINAL_v2.&#8221; Folders buried 8 levels deep with names I made up in 2003 and haven&#8217;t thought about since.</p><p>At work, I help manage around 5,500 virtual desktops running on VMware ESXi. Before that, I spent years on the server side; I&#8217;ve probably built and retired over 15,000 virtual servers throughout my career. I can script my way through complex VMware migrations without breaking a sweat. But ask me to find that PDF of my home insurance policy? Yeah. Good luck with that.</p><p>If this sounds familiar, keep reading.</p><h2>The Problem Nobody Talks About</h2><p>Digital clutter sneaks up on you. It builds quietly, one &#8220;I&#8217;ll organize this later&#8221; at a time. Then suddenly you&#8217;re staring at a search bar, trying to remember which of four cloud services might have the document you need.</p><p>Productivity gurus love to say, &#8220;Just pick a system.&#8221; Easy for them. They&#8217;re usually not dealing with:</p><ul><li><p>Work files that absolutely must stay separate from personal stuff</p></li><li><p>Sensitive documents that need encrypted storage</p></li><li><p>Collaborative projects scattered across different platforms</p></li><li><p>Years of accumulated digital life that doesn&#8217;t fit neatly anywhere</p></li></ul><p>I tried everything. Color-coded folders. Strict naming conventions. Applied the &#8220;inbox zero&#8221; mindset to my files. Each approach worked for maybe three weeks. Then chaos won. It always does.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nt55!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9836e88-6b06-466e-99d4-c02df98f5b28_800x1200.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nt55!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9836e88-6b06-466e-99d4-c02df98f5b28_800x1200.png 424w, https://substackcdn.com/image/fetch/$s_!nt55!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9836e88-6b06-466e-99d4-c02df98f5b28_800x1200.png 848w, https://substackcdn.com/image/fetch/$s_!nt55!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9836e88-6b06-466e-99d4-c02df98f5b28_800x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!nt55!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9836e88-6b06-466e-99d4-c02df98f5b28_800x1200.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nt55!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9836e88-6b06-466e-99d4-c02df98f5b28_800x1200.png" width="800" height="1200" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a9836e88-6b06-466e-99d4-c02df98f5b28_800x1200.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1200,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:386667,&quot;alt&quot;:&quot;from left to right, a laptop, a desktop, and a smart phone all displaying file chaos as they connect above into the various cloud files chaos&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://astgl.com/i/180863482?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9836e88-6b06-466e-99d4-c02df98f5b28_800x1200.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="from left to right, a laptop, a desktop, and a smart phone all displaying file chaos as they connect above into the various cloud files chaos" title="from left to right, a laptop, a desktop, and a smart phone all displaying file chaos as they connect above into the various cloud files chaos" srcset="https://substackcdn.com/image/fetch/$s_!nt55!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9836e88-6b06-466e-99d4-c02df98f5b28_800x1200.png 424w, https://substackcdn.com/image/fetch/$s_!nt55!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9836e88-6b06-466e-99d4-c02df98f5b28_800x1200.png 848w, https://substackcdn.com/image/fetch/$s_!nt55!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9836e88-6b06-466e-99d4-c02df98f5b28_800x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!nt55!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa9836e88-6b06-466e-99d4-c02df98f5b28_800x1200.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>That&#8217;s when I stumbled onto Johnny Decimal, on Reddit, of course.</p><h2>A System That Actually Made Sense</h2><p><a href="https://johnnydecimal.com/">Johnny Decimal is a file organization methodology</a> created by Johnny Noble. The idea is simple: you get a maximum of 10 areas (your broad categories), and each area can hold a maximum of 10 categories (more specific groupings). Every single file gets a unique ID based on where it belongs.</p><p>Instead of wading through <code>/Documents/Work/Projects/2024/Client_ABC/Reports/Final/</code>, you end up with something like <code>32.14 Client ABC Q3 Report</code>.</p><p>The constraints are the whole point. When you limit yourself to 10 areas and 10 categories per area, you actually have to think about how you organize things. Nothing goes deeper than two levels. Every file has a home. You can tell someone &#8220;it&#8217;s in 32.14&#8221; and they know exactly where to look.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ouJa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5cadb8a-2853-4656-aecc-f4f7775aaaf9_788x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ouJa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5cadb8a-2853-4656-aecc-f4f7775aaaf9_788x800.png 424w, https://substackcdn.com/image/fetch/$s_!ouJa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5cadb8a-2853-4656-aecc-f4f7775aaaf9_788x800.png 848w, https://substackcdn.com/image/fetch/$s_!ouJa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5cadb8a-2853-4656-aecc-f4f7775aaaf9_788x800.png 1272w, https://substackcdn.com/image/fetch/$s_!ouJa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5cadb8a-2853-4656-aecc-f4f7775aaaf9_788x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ouJa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5cadb8a-2853-4656-aecc-f4f7775aaaf9_788x800.png" width="788" height="800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e5cadb8a-2853-4656-aecc-f4f7775aaaf9_788x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:788,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:241446,&quot;alt&quot;:&quot;folder view of johnny decimal file system on a Mac computer&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://astgl.com/i/180863482?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5cadb8a-2853-4656-aecc-f4f7775aaaf9_788x800.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="folder view of johnny decimal file system on a Mac computer" title="folder view of johnny decimal file system on a Mac computer" srcset="https://substackcdn.com/image/fetch/$s_!ouJa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5cadb8a-2853-4656-aecc-f4f7775aaaf9_788x800.png 424w, https://substackcdn.com/image/fetch/$s_!ouJa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5cadb8a-2853-4656-aecc-f4f7775aaaf9_788x800.png 848w, https://substackcdn.com/image/fetch/$s_!ouJa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5cadb8a-2853-4656-aecc-f4f7775aaaf9_788x800.png 1272w, https://substackcdn.com/image/fetch/$s_!ouJa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5cadb8a-2853-4656-aecc-f4f7775aaaf9_788x800.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">Johnny Decimal Folder Structure</figcaption></figure></div><p>I read through Johnny&#8217;s documentation, and something just clicked. This wasn&#8217;t some organizational B.S. that would fade in six months. It&#8217;s a real file organization system for thinking about how information connects to other information.</p><p>But I had a problem.</p><h2>The Gap Between Theory and My Reality</h2><p>Johnny Decimal works great when you&#8217;re starting fresh with one file system. I was looking at four cloud services, two machines, and years of accumulated chaos that all needed to be cataloged, cross-referenced, and migrated.</p><p>I needed more than a methodology. I needed a tool.</p><p>Here&#8217;s what I was looking for:</p><ul><li><p>A central index to track where everything lives across all my storage platforms</p></li><li><p>A way to assign and manage Johnny Decimal IDs without going crazy</p></li><li><p>Something that could grow with me as I slowly brought order to the mess</p></li></ul><p>I searched for existing solutions. Some solid tools exist, but nothing quite fit my multi-platform, sprawling-digital-life situation.</p><p>So I built it myself. With an unusual partner helping me along the way.</p><p><em>Next time: What it actually looks like to build an app with AI as your collaborator&#8212;the process, the tool I created, and what I learned about this new kind of partnership.</em></p><p><strong>Have you tried the Johnny Decimal file system? Struggled with multi-cloud chaos? I&#8217;d love to hear your experiences in the comments.</strong></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/i-had-files-scattered-across-4-clouds/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/i-had-files-scattered-across-4-clouds/comments"><span>Leave a comment</span></a></p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/i-had-files-scattered-across-4-clouds?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading As The Geek Learns! This post is public, so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/i-had-files-scattered-across-4-clouds?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/i-had-files-scattered-across-4-clouds?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><p></p>]]></content:encoded></item><item><title><![CDATA[Much to Learn, There Always Is]]></title><description><![CDATA[After 25 years in IT and 15,000+ VMs, I'm still learning. Join me for practical PowerCLI tutorials, VMware automation tips, and lessons from the trenches.]]></description><link>https://astgl.com/p/much-to-learn-there-always-is-05e</link><guid isPermaLink="false">https://astgl.com/p/much-to-learn-there-always-is-05e</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Sat, 06 Dec 2025 22:37:39 GMT</pubDate><enclosure url="https://api.substack.com/feed/podcast/180915494/cb03a96956c21366f4493e3089ecf701.mp3" length="0" type="audio/mpeg"/><content:encoded><![CDATA[<h3>I&#8217;ve been doing this for a while.</h3><p>Twenty-five years of systems engineering. Somewhere around 15,000 virtual machines under my watch (if you count VDI). Countless PowerShell scripts, automation workflows, and middle-of-the-night troubleshooting sessions. I&#8217;ve seen technologies come and go, watched VMware evolve from a curiosity to the backbone of enterprise infrastructure, and learned more from my mistakes than I&#8217;d care to admit.</p><p>So why start writing now?</p><h4><strong>Because I&#8217;m still learning.</strong></h4><p>That might sound strange. After a quarter century, shouldn&#8217;t I have it all figured out? But here&#8217;s what I&#8217;ve discovered: the moment you think you&#8217;ve mastered something is usually the moment before it changes completely. The best engineers I know, the ones who&#8217;ve lasted, who&#8217;ve stayed sharp, are the ones who never stopped being students.</p><p>That&#8217;s what this newsletter is about.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!B0FY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedc56c1e-b42b-4f62-886e-65fdaca40795_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!B0FY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedc56c1e-b42b-4f62-886e-65fdaca40795_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!B0FY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedc56c1e-b42b-4f62-886e-65fdaca40795_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!B0FY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedc56c1e-b42b-4f62-886e-65fdaca40795_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!B0FY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedc56c1e-b42b-4f62-886e-65fdaca40795_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!B0FY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedc56c1e-b42b-4f62-886e-65fdaca40795_1200x630.png" width="1200" height="630" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/edc56c1e-b42b-4f62-886e-65fdaca40795_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:630,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:44936,&quot;alt&quot;:&quot;A winding path stretches toward a glowing horizon, with floating code snippets like \&quot;Get-VM\&quot; and \&quot;Connect-VIServer\&quot; scattered across a gradient sky of deep blue and teal, representing the ongoing journey of learning in IT.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://astgl.substack.com/i/180915494?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedc56c1e-b42b-4f62-886e-65fdaca40795_1200x630.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A winding path stretches toward a glowing horizon, with floating code snippets like &quot;Get-VM&quot; and &quot;Connect-VIServer&quot; scattered across a gradient sky of deep blue and teal, representing the ongoing journey of learning in IT." title="A winding path stretches toward a glowing horizon, with floating code snippets like &quot;Get-VM&quot; and &quot;Connect-VIServer&quot; scattered across a gradient sky of deep blue and teal, representing the ongoing journey of learning in IT." srcset="https://substackcdn.com/image/fetch/$s_!B0FY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedc56c1e-b42b-4f62-886e-65fdaca40795_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!B0FY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedc56c1e-b42b-4f62-886e-65fdaca40795_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!B0FY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedc56c1e-b42b-4f62-886e-65fdaca40795_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!B0FY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedc56c1e-b42b-4f62-886e-65fdaca40795_1200x630.png 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><figcaption class="image-caption">The path forward never ends &#8212; and that&#8217;s what makes it interesting.</figcaption></figure></div><h4><strong>What to expect</strong></h4><p>I&#8217;m not here to pretend I have all the answers. Instead, I&#8217;ll share:</p><ul><li><p><strong>What I&#8217;m learning</strong> &#8212; New tools, techniques, and approaches I&#8217;m exploring</p></li><li><p><strong>What actually works</strong> &#8212; Practical solutions tested in real production environments, not just lab demos</p></li><li><p><strong>What I&#8217;ve built</strong> &#8212; Apps and automation I&#8217;ve created to solve my own problems (and might solve yours too)</p></li><li><p><strong>What I got wrong</strong> &#8212; Because occasionally the best lessons come from failures</p></li></ul><p>If you work in IT, especially if you&#8217;re managing VMware infrastructure or trying to level up your PowerCLI skills, I think you&#8217;ll find something useful here.</p><h4><strong>A bit about me</strong></h4><p>I&#8217;m a systems engineer at a large healthcare organization in Florida, where I manage enterprise VMware infrastructure. I&#8217;ve spent years automating repetitive tasks, building tools to make my life easier, and figuring out how to do more with less (sound familiar?).</p><p>Outside the day job, I&#8217;m working on training courses for IT professionals who want to master PowerCLI and VMware automation. I&#8217;ve also built a few apps, including KlockThingy&#8212;a time-tracking tool that came out of my wife&#8217;s frustration with what she calls &#8216;Clocky Math.&#8217; It was vital that she log her hours more efficiently as a remote contract worker. She also coined the name.</p><h4><strong>Why &#8220;As The Geek Learns&#8221;?</strong></h4><p>The name says it all. I&#8217;m a geek. I learn things. I write about what I learn.</p><p>There&#8217;s a Yoda quote I&#8217;ve always loved: <em><strong>&#8220;Much to learn, you still have.&#8221; </strong></em>I have adapted that quote to reflect my lifelong learning experience.</p><p><em><strong>&#8220;Much to learn, there always is&#8221;</strong></em></p><p>It&#8217;s a reminder that expertise isn&#8217;t a destination; it&#8217;s a direction. No matter how long you&#8217;ve been at this, there&#8217;s always something new to discover.</p><p>I hope you&#8217;ll come along for the ride.</p><h4><strong>What&#8217;s next</strong></h4><p>In upcoming posts, I&#8217;ll be sharing:</p><ul><li><p>A deep dive into the PowerCLI automation techniques I use daily</p></li><li><p>Behind the scenes of building and shipping my first app</p></li><li><p>Practical tips for managing large-scale VMware environments</p></li><li><p>And whatever else I&#8217;m learning along the way</p></li></ul><p>If any of that sounds interesting, you&#8217;re in the right place.</p><p><em>Thanks for being here.</em></p><p><em><strong>Always a student. Sometimes a teacher.</strong></em></p><p>&#8212; James</p>]]></content:encoded></item><item><title><![CDATA[Much to Learn, There Always Is]]></title><description><![CDATA[After 25 years in IT and 15,000+ VMs, I'm still learning. Join me for practical PowerCLI tutorials, VMware automation tips, and lessons from the trenches.]]></description><link>https://astgl.com/p/much-to-learn-there-always-is</link><guid isPermaLink="false">https://astgl.com/p/much-to-learn-there-always-is</guid><dc:creator><![CDATA[James Cruce]]></dc:creator><pubDate>Sat, 06 Dec 2025 20:17:31 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!z4YF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F569f881b-d6dd-436d-8068-cd9e2b13f261_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://astgl.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 As The Geek Learns! 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></p><h3>I&#8217;ve been doing this for a while.</h3><p>Twenty-five years of systems engineering. Somewhere around 15,000 virtual machines under my watch (if you count VDI). Countless PowerShell scripts, automation workflows, and middle-of-the-night troubleshooting sessions. I&#8217;ve seen technologies come and go, watched VMware evolve from a curiosity to the backbone of enterprise infrastructure, and learned more from my mistakes than I&#8217;d care to admit.</p><p>So why start writing now?</p><h4><strong>Because I&#8217;m still learning.</strong></h4><p>That might sound strange. After a quarter century, shouldn&#8217;t I have it all figured out? But here&#8217;s what I&#8217;ve discovered: the moment you think you&#8217;ve mastered something is usually the moment before it changes completely. The best engineers I know, the ones who&#8217;ve lasted, who&#8217;ve stayed sharp, are the ones who never stopped being students.</p><p>That&#8217;s what this newsletter is about.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!z4YF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F569f881b-d6dd-436d-8068-cd9e2b13f261_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!z4YF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F569f881b-d6dd-436d-8068-cd9e2b13f261_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!z4YF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F569f881b-d6dd-436d-8068-cd9e2b13f261_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!z4YF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F569f881b-d6dd-436d-8068-cd9e2b13f261_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!z4YF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F569f881b-d6dd-436d-8068-cd9e2b13f261_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!z4YF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F569f881b-d6dd-436d-8068-cd9e2b13f261_1200x630.png" width="1200" height="630" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/569f881b-d6dd-436d-8068-cd9e2b13f261_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:630,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:44936,&quot;alt&quot;:&quot;A winding path stretches toward a glowing horizon, with floating code snippets like \&quot;Get-VM\&quot; and \&quot;Connect-VIServer\&quot; scattered across a gradient sky of deep blue and teal, representing the ongoing journey of learning in IT.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://astgl.substack.com/i/180903776?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F569f881b-d6dd-436d-8068-cd9e2b13f261_1200x630.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A winding path stretches toward a glowing horizon, with floating code snippets like &quot;Get-VM&quot; and &quot;Connect-VIServer&quot; scattered across a gradient sky of deep blue and teal, representing the ongoing journey of learning in IT." title="A winding path stretches toward a glowing horizon, with floating code snippets like &quot;Get-VM&quot; and &quot;Connect-VIServer&quot; scattered across a gradient sky of deep blue and teal, representing the ongoing journey of learning in IT." srcset="https://substackcdn.com/image/fetch/$s_!z4YF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F569f881b-d6dd-436d-8068-cd9e2b13f261_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!z4YF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F569f881b-d6dd-436d-8068-cd9e2b13f261_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!z4YF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F569f881b-d6dd-436d-8068-cd9e2b13f261_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!z4YF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F569f881b-d6dd-436d-8068-cd9e2b13f261_1200x630.png 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><figcaption class="image-caption">The path forward never ends&#8212;and that&#8217;s what makes it interesting.</figcaption></figure></div><p></p><h4><strong>What to expect</strong></h4><p>I&#8217;m not here to pretend I have all the answers. Instead, I&#8217;ll share:</p><ul><li><p><strong>What I&#8217;m learning</strong> &#8212; New tools, techniques, and approaches I&#8217;m exploring</p></li><li><p><strong>What actually works</strong> &#8212; Practical solutions tested in real production environments, not just lab demos</p></li><li><p><strong>What I&#8217;ve built</strong> &#8212; Apps and automation I&#8217;ve created to solve my own problems (and might solve yours too)</p></li><li><p><strong>What I got wrong</strong> &#8212; Because occasionally the best lessons come from failures</p></li></ul><p>If you work in IT, especially if you&#8217;re managing VMware infrastructure or trying to level up your PowerCLI skills, I think you&#8217;ll find something useful here.</p><h4><strong>A bit about me</strong></h4><p>I&#8217;m a systems engineer at a large healthcare organization in Florida, where I manage enterprise VMware infrastructure. I&#8217;ve spent years automating repetitive tasks, building tools to make my life easier, and figuring out how to do more with less (sound familiar?).</p><p>Outside the day job, I&#8217;m working on training courses for IT professionals who want to master PowerCLI and VMware automation. I&#8217;ve also built a few apps, including KlockThingy&#8212;a time-tracking tool that came out of my wife&#8217;s frustration with what she calls &#8216;Clocky Math.&#8217; It was vital that she log her hours more efficiently as a remote contract worker. She also coined the name.</p><h4><strong>Why &#8220;As The Geek Learns&#8221;?</strong></h4><p>The name says it all. I&#8217;m a geek. I learn things. I write about what I learn.</p><p>There&#8217;s a Yoda quote I&#8217;ve always loved: <em><strong>&#8220;Much to learn, you still have.&#8221; </strong></em> I have adapted that quote to reflect my lifelong learning experience. </p><p><em><strong>&#8220;Much to learn, there always is&#8221; </strong></em></p><p>It&#8217;s a reminder that expertise isn&#8217;t a destination; it&#8217;s a direction. No matter how long you&#8217;ve been at this, there&#8217;s always something new to discover.</p><p>I hope you&#8217;ll come along for the ride.</p><h4><strong>What&#8217;s next</strong></h4><p>In upcoming posts, I&#8217;ll be sharing:</p><ul><li><p>A deep dive into the PowerCLI automation techniques I use daily</p></li><li><p>Behind the scenes of building and shipping my first app</p></li><li><p>Practical tips for managing large-scale VMware environments</p></li><li><p>And whatever else I&#8217;m learning along the way</p></li></ul><p>If any of that sounds interesting, you&#8217;re in the right place.</p><p><em>Thanks for being here.</em></p><p><em><strong>Always a student. Sometimes a teacher.</strong></em></p><p>&#8212; James</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/much-to-learn-there-always-is?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading As The Geek Learns! This post is public, so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://astgl.com/p/much-to-learn-there-always-is?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://astgl.com/p/much-to-learn-there-always-is?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><p></p>]]></content:encoded></item></channel></rss>