<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ivan Misic</title>
    <description>The latest articles on DEV Community by Ivan Misic (@imisic).</description>
    <link>https://dev.to/imisic</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3983583%2Fb8758a38-885d-4fc0-9791-d3655df6804f.png</url>
      <title>DEV Community: Ivan Misic</title>
      <link>https://dev.to/imisic</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/imisic"/>
    <language>en</language>
    <item>
      <title>How I Built My Site With Claude Code</title>
      <dc:creator>Ivan Misic</dc:creator>
      <pubDate>Thu, 16 Jul 2026 14:30:20 +0000</pubDate>
      <link>https://dev.to/imisic/how-i-built-my-site-with-claude-code-2ojh</link>
      <guid>https://dev.to/imisic/how-i-built-my-site-with-claude-code-2ojh</guid>
      <description>&lt;p&gt;I built this website from scratch over about three weeks of actual work. A week during holiday, a handful of weekends, and some late nights in between. No WordPress. No Laravel. No React. No Tailwind. Just PHP, vanilla JavaScript, a custom CSS design system, and Claude Code as my development partner.&lt;/p&gt;

&lt;p&gt;Here's the full story: what I built, how I built it, what worked, what didn't, and what I'd change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Build From Scratch?
&lt;/h2&gt;

&lt;p&gt;After years of managing products built on frameworks and platforms, I wanted to understand what's actually under the hood, not just the abstraction sitting on top of it.&lt;/p&gt;

&lt;p&gt;But there was another reason. AI-assisted development is everywhere now, and I'm a strong believer that you need to understand something before you can manage it or benefit from it in your work. You need to know its strengths and weaknesses firsthand. Building a real project with Claude Code was about learning how AI works in practice. Writing code, yes, but also planning, designing, strategizing, and problem-solving.&lt;/p&gt;

&lt;p&gt;So I set some rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No backend frameworks.&lt;/strong&gt; No Laravel, no Symfony. Custom MVC from scratch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No frontend frameworks.&lt;/strong&gt; No React, no Vue, no jQuery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No CSS frameworks.&lt;/strong&gt; No Tailwind, no Bootstrap. Custom design system with tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build it properly.&lt;/strong&gt; Database migrations, service layer, feature flags, deployment pipeline. Not a toy project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Claude Code for implementation.&lt;/strong&gt; I'd make all the architecture and design decisions. Claude would write the code.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;p&gt;What powers this site:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;th&gt;Details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;PHP 8.2+&lt;/td&gt;
&lt;td&gt;Custom MVC framework with strict typing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Vanilla ES6+&lt;/td&gt;
&lt;td&gt;~3,700 lines across 10 focused scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSS&lt;/td&gt;
&lt;td&gt;Custom design system&lt;/td&gt;
&lt;td&gt;26 files, ~10,700 lines, BEM + utility classes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;MySQL&lt;/td&gt;
&lt;td&gt;40 migrations tracking schema changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;LiteSpeed&lt;/td&gt;
&lt;td&gt;With cache integration for production&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Custom pipeline&lt;/td&gt;
&lt;td&gt;JSON content sync, PHP build script, Python deploy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No npm. No Composer packages for the frontend. No build tools besides a PHP minifier I wrote myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;The request flow is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request → index.php → Bootstrap → Router → Controller → View
                                     ↓
                                  Service → Model → Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the interesting parts are the constraints I enforced.&lt;/p&gt;

&lt;h3&gt;
  
  
  Strict Layer Separation
&lt;/h3&gt;

&lt;p&gt;Controllers handle HTTP. That's it. They extract request data, check authentication, and call services or models. They never contain business logic.&lt;/p&gt;

&lt;p&gt;Services handle all mutations. Every create, update, and delete goes through a service that validates input, generates slugs, manages cache, and returns a &lt;code&gt;ServiceResult&lt;/code&gt; object. Controllers never touch models directly for writes.&lt;/p&gt;

&lt;p&gt;Models handle persistence. Every model extends &lt;code&gt;BaseModel&lt;/code&gt;, defines a &lt;code&gt;$fillable&lt;/code&gt; whitelist for allowed columns, and uses prepared statements exclusively. No raw SQL anywhere outside of models.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Controller (thin - HTTP concerns only)&lt;/span&gt;
&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BlogPostService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;errorString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Service (business logic)&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;ServiceResult&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;normalizeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$errors&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ServiceResult&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$errors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// slug generation, cache invalidation, reading time calc...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ServiceResult&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$entity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern made the codebase predictable. When something breaks, I know exactly which layer to look at.&lt;/p&gt;

&lt;h3&gt;
  
  
  Feature Flags
&lt;/h3&gt;

&lt;p&gt;Every content type has a feature flag in &lt;code&gt;.env&lt;/code&gt;. Blog, tools, guides, journeys, API specs. When a flag is disabled, the router shows a "Coming Soon" page for public visitors, but the admin panel still shows everything. This means I can build and populate a new section privately, then flip a switch to launch it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;FEATURE_BLOG&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;FEATURE_TOOLS&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;FEATURE_GUIDES&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;FEATURE_NEWS&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;false        # Building this next&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Database Migrations
&lt;/h3&gt;

&lt;p&gt;Every schema change has a migration file with an UP and DOWN section. I can run them forward, roll back the last batch, and track what's been applied. Works via CLI or admin UI.&lt;/p&gt;

&lt;p&gt;40 migrations and counting. We introduced the migration system a few iterations in, so the actual number of schema changes is higher than the tracked ones. But from the initial blog schema through OAuth tables, analytics, and content sync, every change since has been tracked and reversible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content Pipeline
&lt;/h3&gt;

&lt;p&gt;Blog posts are written in Markdown, stored in the database, and rendered to HTML at runtime. No pre-rendered cache. The content sync system exports everything to a JSON bundle (slug-based, not ID-based) that can be imported on production. View counts and analytics are never overwritten during sync.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Brutalist Design
&lt;/h2&gt;

&lt;p&gt;I went with "Brutalist Bold." Dark backgrounds, 2px borders everywhere, zero border-radius, monospace fonts for labels and metadata, and Electric Lime (#D4FF00) as the accent color.&lt;/p&gt;

&lt;p&gt;&lt;a href="/images/blog/redesign-v1-homepage.png" class="article-body-image-wrapper"&gt;&lt;img src="/images/blog/redesign-v1-homepage.png" alt="Homepage of the original ivanmisic.net design: black canvas, Electric Lime #D4FF00 accent, oversized outlined "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Heads up.&lt;/strong&gt; The site you're reading right now isn't this. The v1 brutalist build was replaced by a Station warm-noir design in April 2026. The full redesign story (four calendar days, one person, end-to-end) is in &lt;a href="https://dev.to/blog/digital-transformation/four-days-one-person-redesign"&gt;Four Calendar Days, One Person, One Full Redesign&lt;/a&gt;. The rest of this post is the original v1 build story, kept as-is.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Why brutalist? Two reasons.&lt;/p&gt;

&lt;p&gt;First, constraints make decisions faster. When border-radius is 0, you never debate "should this be 4px or 8px?" When shadows aren't allowed, you use borders. When you only have one accent color, you don't waste time on color palettes. Every rule I added was one fewer decision to make.&lt;/p&gt;

&lt;p&gt;Second, it looks distinctive. Most sites lean on rounded corners and soft gradients, so sharp edges stand out. The site doesn't look like a template because it isn't one.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Design Token System
&lt;/h3&gt;

&lt;p&gt;Everything lives in &lt;code&gt;tokens.css&lt;/code&gt;. Colors, spacing, font sizes, border widths, transitions. Components reference tokens only. Never a hardcoded value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* tokens.css */&lt;/span&gt;
&lt;span class="nt"&gt;--color-primary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;#D4FF00&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;--color-bg&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;#0&lt;/span&gt;&lt;span class="nt"&gt;a0a0a&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;--space-4&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="nt"&gt;rem&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;--space-8&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="nt"&gt;rem&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;--border-width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;--font-mono&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'JetBrains Mono'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;monospace&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system supports dark/light themes and multiple accent colors (lime, cyan, rose) through CSS custom properties. Switching themes means changing token values, not rewriting components.&lt;/p&gt;

&lt;p&gt;The v1 build ran to 48 CSS files and over 15,500 lines. Every component in its own file, utilities loading last so they override components. It was more CSS than most people would write for a personal site, but the token system kept it maintainable. (The v2 redesign later consolidated a lot of it; today's counts are in the table further down.)&lt;/p&gt;

&lt;p&gt;&lt;a href="/images/blog/redesign-v1-article.png" class="article-body-image-wrapper"&gt;&lt;img src="/images/blog/redesign-v1-article.png" alt="Brutalist article layout in action: stark black canvas, sticky table of contents on the left, lime accents on category pills and inline UPDATE keyword, mono-uppercase navigation, hairline rules between sections"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Working With Claude Code
&lt;/h2&gt;

&lt;p&gt;Everyone asks about this part.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Blew My Mind: The Speed
&lt;/h3&gt;

&lt;p&gt;The speed changed how I think about building things. Tasks I'd estimate taking a full day were done in an hour or two. And not just boilerplate. Claude handled complex database queries with proper indexing, CSS architecture decisions, security patterns (CSRF tokens, prepared statements, rate limiting), and deployment pipeline design.&lt;/p&gt;

&lt;p&gt;I could describe what I wanted in plain language and get working, production-quality code back. "Build me a service layer for blog posts with validation, slug generation, and cache invalidation." Done. "Create a migration system that supports rollback by batch." Done.&lt;/p&gt;

&lt;p&gt;It felt like pair programming with a fast, patient senior developer who never needs a coffee break.&lt;/p&gt;

&lt;h3&gt;
  
  
  The CLAUDE.md File
&lt;/h3&gt;

&lt;p&gt;Early on, I discovered that Claude would "forget" architectural decisions across sessions. It would create a new button style when one already existed, or use a different pattern for error handling than what we'd established.&lt;/p&gt;

&lt;p&gt;The fix was a detailed &lt;code&gt;CLAUDE.md&lt;/code&gt; file at the project root. Design tokens, naming conventions, architectural rules, component inventory. Claude reads it at the start of every session. I also created 15 rules files in &lt;code&gt;.claude/rules/&lt;/code&gt; covering everything from CSS standards to database conventions. (I dig into this more in &lt;a href="https://dev.to/blog/ai-tools/claude-code-bigger-projects"&gt;Making Claude Code Work on Bigger Projects&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;This persistent memory was a turning point. Once the rules existed, Claude stopped inventing new patterns and started following the established ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where Claude Struggled
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Over-engineering.&lt;/strong&gt; Claude tends to add more abstraction than needed. "Just a simple function" would come back with an abstract base class, two interfaces, and a factory. I spent a lot of time saying "simpler."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS consistency.&lt;/strong&gt; Without strict rules, Claude would create duplicate CSS classes. A new card component when &lt;code&gt;.card-regular&lt;/code&gt; already existed. New button variants when &lt;code&gt;.btn--primary&lt;/code&gt; was right there. The rules files fixed this, but only after I'd cleaned up several rounds of duplicate styles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design taste.&lt;/strong&gt; Claude doesn't have it. The brutalist aesthetic was entirely my vision. Claude executed it well once I explained what I wanted, but it would never have suggested "let's do 2px borders with no border-radius and lime green accents." Every visual decision was mine.&lt;/p&gt;

&lt;p&gt;Two more were subtler. The first was context drift. On long sessions with many changes, Claude would sometimes lose track of earlier decisions. Keeping sessions focused on one task at a time helped. So did the rules files.&lt;/p&gt;

&lt;p&gt;The second is harder to explain. I came to call them the stupid sessions. Sometimes Claude would just... stop working. Not crash. Not error out. It would keep responding, but the quality would fall off a cliff. Simple tasks it had handled fine an hour ago would produce nonsense. It ignored rules it had been following all session. It made changes that contradicted what it had just done.&lt;/p&gt;

&lt;p&gt;My theory: context overload. After 30-45 minutes of complex work, something breaks down. The fix was surprisingly simple. Close everything. Walk away. Come back a few hours later, start a fresh session, and Claude would pick up exactly where it left off like nothing happened. No explanation. No apology. Just back to being competent.&lt;/p&gt;

&lt;p&gt;It turned into a rhythm. Work intensely for 30-45 minutes. If Claude starts struggling with things it should know, don't fight it. Don't retry the same prompt five times hoping for a different result. Just stop. Fresh session later. It's frustrating in the moment, but it's faster than arguing with a confused AI for another hour.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Worked Well
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Natural language architecture.&lt;/strong&gt; I could say "the controller should only handle HTTP, the service should handle business logic" and Claude would implement that separation consistently across every controller and service it created.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Refactoring at scale.&lt;/strong&gt; "Extract all category CRUD into a shared trait." Claude would read the existing implementations, identify the common patterns, create the trait, and update both services. In one pass.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security patterns.&lt;/strong&gt; Claude was better at security than I expected. Column whitelisting, prepared statements, CSRF validation, rate limiting. It would proactively add security measures I hadn't asked for.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers
&lt;/h2&gt;

&lt;p&gt;Three weeks of focused work produced the first version. The numbers below are where the site stands today, after the v2 redesign and a year of iteration on top of that initial sprint:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PHP files&lt;/td&gt;
&lt;td&gt;204&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Controllers&lt;/td&gt;
&lt;td&gt;39&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Models&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Services&lt;/td&gt;
&lt;td&gt;43&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Views&lt;/td&gt;
&lt;td&gt;78&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSS files&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JS files&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database migrations&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lines of PHP&lt;/td&gt;
&lt;td&gt;~48,700&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lines of CSS&lt;/td&gt;
&lt;td&gt;~10,700&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lines of JS&lt;/td&gt;
&lt;td&gt;~3,700&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude rules files&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Why a personal site has this much code
&lt;/h3&gt;

&lt;p&gt;A reasonable read of the table above is "why does a blog have ~48,700 lines of PHP?" The answer is that the blog is one feature out of around a dozen. Those numbers power all of this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Public side.&lt;/strong&gt; Blog with categories, tags, related posts, and full-text search. Tools directory with ratings and click tracking. Step-by-step guides with modules and content gating. RSS-driven news aggregation with article clustering. About / Now / Contact pages. User accounts with OAuth (Google, GitHub, LinkedIn) and magic-link login. SEO infrastructure: dynamic sitemap, robots.txt, structured data, canonical handling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Admin, the iceberg.&lt;/strong&gt; This is where most of the code lives, and it's bigger than the public site. 21 admin controllers covering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dashboard with server-side analytics (no GA, no third-party tracking)&lt;/li&gt;
&lt;li&gt;Blog editor, media manager, category and tag management&lt;/li&gt;
&lt;li&gt;Tools manager with click-tracking review&lt;/li&gt;
&lt;li&gt;Guides editor with module-level authoring&lt;/li&gt;
&lt;li&gt;News management (sources, briefings, manual curation)&lt;/li&gt;
&lt;li&gt;Marketing calendar for scheduling LinkedIn, Twitter and Reddit posts, with status tracking and links back to source articles&lt;/li&gt;
&lt;li&gt;Sticky-note system for leaving notes attached to any URL on the site&lt;/li&gt;
&lt;li&gt;Contacts and user management&lt;/li&gt;
&lt;li&gt;Redirects, migrations runner, content sync (export/import bundles between local and production)&lt;/li&gt;
&lt;li&gt;Maintenance actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure underneath.&lt;/strong&gt; Custom MVC with strict typing. Service layer with thin controllers. Migrations system with rollback by batch. Rate limiting on auth and external API calls. CSRF on every state-changing route. A CLI content workflow (&lt;code&gt;pull&lt;/code&gt;/&lt;code&gt;diff&lt;/code&gt;/&lt;code&gt;push&lt;/code&gt;) so AI tools can edit DB content safely without losing analytics or skipping cache invalidation. Build pipeline split into public and admin. Python deploy pipeline. 15 review skill rules that gate every meaningful chunk of work before it merges.&lt;/p&gt;

&lt;p&gt;So the ~48,700 PHP lines are doing more than running a blog. They're running a small CMS plus a personal ops layer. Claude Code made building all of that possible in the time I had.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Came After
&lt;/h3&gt;

&lt;p&gt;The site kept growing after that initial build sprint. A few additions worth mentioning:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Marketing calendar.&lt;/strong&gt; A full calendar view for scheduling social media posts across LinkedIn, Twitter, and Reddit. Drag posts between dates, toggle statuses with a click, link posts to blog articles. Built it in a single session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Admin notes system.&lt;/strong&gt; As an admin, I can leave notes on any page of the site. Sticky notes attached to URLs, basically. I browse the site, spot something that needs fixing or an idea for improvement, and drop a note right there. Later I export all notes, feed them to Claude Code, and work through them. It's how these very updates to this article happened.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;News aggregation.&lt;/strong&gt; An RSS-based system that pulls industry news from sources I curate, clusters related articles, and helps me stay on top of trends relevant to my writing.&lt;/p&gt;

&lt;p&gt;Each of these was a "Claude Code afternoon." Describe what I want, review what comes back, iterate until it's right. The pattern never gets old.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd Do Differently
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Set up the design token system from day one.&lt;/strong&gt; I started with ad-hoc CSS values and had to retrofit tokens later. Painful. If you're building a custom design system, define your tokens first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shorter sessions.&lt;/strong&gt; Long Claude Code sessions led to context drift and inconsistency. Focused sessions (one feature, one PR, done) worked much better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rules files earlier.&lt;/strong&gt; I created them after discovering inconsistencies. Should have started with a basic set from the beginning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automate cache busting sooner.&lt;/strong&gt; Manual asset versioning was tedious. The build script handles it now, but I should have built that in week one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Budget time to understand what Claude builds.&lt;/strong&gt; This one caught me off guard. In a typical 30-45 minute session, Claude would build more than I asked for. Not in a bad way. It would see logical next steps and implement them. A service layer would come with cache invalidation I hadn't mentioned. A controller would include rate limiting I hadn't requested. Good additions, but I'd end up spending more time reading and understanding the code than it took Claude to write it.&lt;/p&gt;

&lt;p&gt;Then I'd need to document the patterns in my rules files so Claude would stay consistent. Which took even longer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The writing was fast. The learning and documenting is what ate the time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you're using Claude Code for anything serious, accept that you need to understand what it's doing, how it's doing it, and why. You're the director, sure, but also the quality inspector, the technical writer, and the institutional memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The site is live and I'm writing content. Blog posts about product management and digital transformation. The tools directory is growing. More guides are in progress.&lt;/p&gt;

&lt;p&gt;I plan to keep building in public and updating this post as the site evolves. New content types (journeys, case studies) are in the pipeline, gated behind feature flags and waiting for content.&lt;/p&gt;

&lt;p&gt;If you're considering building something with Claude Code, my one-sentence takeaway:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Claude Code takes the tedious parts off your plate. Deciding what to build is still your job.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you want a more structured walkthrough, I've put together a &lt;a href="https://dev.to/guides/claude-code-guide"&gt;Claude Code Guide&lt;/a&gt; that covers a simpler path to a similar outcome.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>webdev</category>
      <category>ai</category>
      <category>career</category>
    </item>
    <item>
      <title>My AI Was Smart. It Just Couldn't See My Job.</title>
      <dc:creator>Ivan Misic</dc:creator>
      <pubDate>Sun, 28 Jun 2026 15:30:04 +0000</pubDate>
      <link>https://dev.to/imisic/obsidian-holds-the-notes-claude-does-the-work-5ebe</link>
      <guid>https://dev.to/imisic/obsidian-holds-the-notes-claude-does-the-work-5ebe</guid>
      <description>&lt;p&gt;Every AI keynote shows the same demo. The assistant reads your inbox, pulls up the right document, joins your meeting, and reminds you what you promised someone last Tuesday. It looks like magic. Then you close the tab, go back to your real job, and none of it is real.&lt;/p&gt;

&lt;p&gt;Think about what your job actually runs on. The decision you sent by email three weeks ago. The one slide that mattered in a sixty-slide deck. Who promised what in a meeting nobody wrote down. That pile is your real memory of the work, and it sits scattered across a dozen apps with no reason to talk to each other. People call that pile a second brain. Yours is useless to an AI that can't reach it.&lt;/p&gt;

&lt;p&gt;The model isn't the problem. It's plenty smart already. The problem is that it's blind. It doesn't know your people, your projects, how your org is wired, or how you like things done. None of that is in the model. It's in everything you've already written down, and the model can't see a word of it. So I spent a few weekends on one question: if nobody is going to hand me the connector, how much of that demo could I build myself?&lt;/p&gt;

&lt;p&gt;If you've watched one of those demos and wondered why nothing like it ever works at your actual job, that gap is the whole story here. The fix is one idea you can use on any AI project, whether or not you ever build a setup like mine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frqs6seopov70t92feq62.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frqs6seopov70t92feq62.jpg" alt="Claude and Obsidian turning scattered work artifacts (email, meetings, documents, notes) into one connected second brain" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The connector gap
&lt;/h2&gt;

&lt;p&gt;The demos skip the boring part. That assistant works because someone wired it into a sandbox where the calendar, the mail, and the documents are one click away. You're watching the one example that was prepped to go smoothly, in an environment built to make it look effortless. Real work is messier than the rehearsal. Plenty of workplaces, for good reasons, won't hand a personal script the keys to your mailbox, and the convenient note-takers want to ship your meeting audio to someone else's cloud. So the moment you care where your data goes, the easy connectors fall away, and you're left with a model that can reason about anything you paste in and reach nothing on its own.&lt;/p&gt;

&lt;p&gt;So you get a strange split. The intelligence is racing ahead and getting cheaper by the month. The plumbing that connects it to your real life is barely moving.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The bottleneck for useful AI is rarely the model. It's whether your data is somewhere the model can reach, and whether you know how to put it to work once it's there.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  So I started building one
&lt;/h2&gt;

&lt;p&gt;Rather than wait for a vendor to ship the connector, I tried building one myself. Not a clever agent. Not a magic prompt. A pipeline. It started as a weekend experiment and quietly turned into something I run most mornings.&lt;/p&gt;

&lt;p&gt;Two tools do the heavy lifting, and both deserve a one-line introduction if they're new to you. &lt;strong&gt;&lt;a href="https://obsidian.md" rel="noopener noreferrer"&gt;Obsidian&lt;/a&gt;&lt;/strong&gt; is a free note app where every note is a plain markdown file on your own disk, linked to the others. The folder that holds all of them is called a vault, and that vault is my second brain. If you'd rather not start from an empty folder, the &lt;a href="https://github.com/imisic/claude-obsidian-vault" rel="noopener noreferrer"&gt;vault template is on GitHub&lt;/a&gt;. &lt;strong&gt;Claude Code&lt;/strong&gt; is Anthropic's AI assistant that runs in your terminal and can actually read and write files on your machine, which is what lets it run the vault instead of just chatting about it. If you've never touched it, I wrote a &lt;a href="https://dev.to/blog/ai-tools/installing-claude-code-five-minutes"&gt;beginner's series on getting started with Claude Code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The idea is simple. Everything from my work life flows into one folder Claude can read. Emails land there. Meeting transcripts land there. So do the documents I get sent and the half-formed notes I write to myself. Once the data sits somewhere the model can see, it can finally do the thing the keynote promised. The whole trick was getting it into the room.&lt;/p&gt;

&lt;p&gt;Plain text matters more than it sounds. A file is the one format a human and an AI can both open, diff, and reason about without anything breaking, which is the same reason I &lt;a href="https://dev.to/blog/ai-tools/safe-way-edit-database-content-ai-coding-tools"&gt;edit this site's content as files instead of running raw SQL against production&lt;/a&gt;. No proprietary format, no lock-in. If every tool I use disappeared tomorrow, the Obsidian vault is still a folder of readable text.&lt;/p&gt;

&lt;h2&gt;
  
  
  One door in, sorted folders out
&lt;/h2&gt;

&lt;p&gt;Everything enters through the same door and leaves sorted. The daily cycle is short:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;New emails, transcripts, documents, and quick notes all land in one &lt;code&gt;00-Inbox&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;Once a day, sometimes every second day when things are quiet, I run a single command. Claude reads the inbox and works out what each file is.&lt;/li&gt;
&lt;li&gt;It cleans each one up, pulls out the people, projects, and action items, and writes a proper note.&lt;/li&gt;
&lt;li&gt;The note goes to the folder it belongs in. The source leaves the inbox, which returns to empty.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The vault itself is a handful of numbered folders, each with one job:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Folder&lt;/th&gt;
&lt;th&gt;What lives there&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;00-Inbox&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The landing zone. Every new file drops here first, then gets sorted out.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;01-Daily&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One note per day, topped with an AI-written morning briefing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;03-Projects&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A file per project or workstream I'm tracking.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;04-People&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A file per person, created the first time they show up in my mail or a meeting.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;05-Interactions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The processed meeting and email notes. The bulk of the vault.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;07-Areas&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Goals and dashboards, like a running list of open tasks.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;08-Reference&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Documents turned into markdown, so a slide deck becomes readable text.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;09-Archive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Finished projects and past quarters, moved out of the way.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fivanmisic.net%2F%2Fimages%2Fblog%2Fai-tools%2Fobsidian-graph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fivanmisic.net%2F%2Fimages%2Fblog%2Fai-tools%2Fobsidian-graph.png" alt="My Obsidian vault rendered as a node graph: a few hundred plain-text notes pulled into one connected web by their links" width="800" height="754"&gt;&lt;/a&gt;&lt;/p&gt;
My real vault as a graph. Each dot is a note, each line a link. What landed as scattered emails, meetings, and documents pulled itself into one connected web of people, projects, and decisions.



&lt;p&gt;Zoom into any one of those dots and you get a file like this. A project note the pipeline keeps current, where every name and decision is a link back out into the graph:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Self-Serve-Checkout&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;active&lt;/span&gt;
&lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[[Ivan-Misic]]"&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;project&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Self-Serve-Checkout&lt;/span&gt;

&lt;span class="gu"&gt;## Key stakeholders&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [[Ivan-Misic]] (owner)
&lt;span class="p"&gt;-&lt;/span&gt; [[Dana-Holt]] (sponsor)
&lt;span class="p"&gt;-&lt;/span&gt; [[Marco-Ruiz]] (engineering)

&lt;span class="gu"&gt;## Open items&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] [[Marco-Ruiz]] confirm the build is feature-complete [due:: 2026-05-16]
&lt;span class="p"&gt;-&lt;/span&gt; [ ] [[Dana-Holt]] sign off on go/no-go criteria [due:: 2026-05-16]

&lt;span class="gu"&gt;## Decisions log&lt;/span&gt;
| Date | Decision | Owner | Status |
|-|-|-|-|
| 2026-05-15 | Target Monday, May 18 for go-live | [[Dana-Holt]] | confirmed |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The folders, the linking conventions, and the Claude Code skills that run them are the part I can hand over, and they're up on GitHub.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"&amp;gt;
        &amp;lt;path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"&amp;gt;&amp;lt;/path&amp;gt;
    &amp;lt;/svg&amp;gt;


    Claude + Obsidian vault template
    PUBLIC REPO · CLONE OR DOWNLOAD ZIP

&amp;lt;a href="https://github.com/imisic/claude-obsidian-vault" rel="noopener"&amp;gt;View on GitHub&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Getting data out of a locked box
&lt;/h2&gt;

&lt;p&gt;Two sources were hard, and both for the same reason: the easy path was off the table.&lt;/p&gt;

&lt;p&gt;For email, wiring straight into the mailbox API wasn't realistic, so I leaned on plumbing that was already there. A background workflow watches my mailbox and writes messages out as plain text files to Microsoft OneDrive. I don't pipe the whole firehose in: the export only fires on mail Outlook flags as important, my VIP senders plus the few I mark by hand, so what reaches the vault is already mail I've decided is worth keeping. OneDrive syncs that folder down to my laptop, and a scheduled task drops the files into my second brain's inbox every few minutes. That's the whole mechanism.&lt;/p&gt;

&lt;p&gt;It felt like a downgrade until I realized plain text was the most reliable interface in the system. No tokens to refresh, no rate limits, no connection to drop at 2am. Each piece can fail on its own without taking the rest down. The fanciest part of the email path is a five-line script that tags messages I sent with a &lt;code&gt;SENT-&lt;/code&gt; prefix, because the export leaves the &lt;code&gt;From:&lt;/code&gt; field empty and that's the simplest way to tell which direction a mail went. The unglamorous fix kept winning.&lt;/p&gt;

&lt;p&gt;Meetings were the other wall, and here I set myself a rule for the fun of it: capture them without handing the audio to someone else's cloud. Half the experiment was finding out whether that was even possible. It is. A small tray app records the call, transcribes it locally with speaker labels, and drops the text into the inbox. That audio never leaves the machine. On my card a one-hour meeting becomes a clean transcript in about six minutes, quicker on a stronger GPU and slower on a weak one, fast enough that the notes are waiting before the next call. The ones I don't catch that way go through a pocket recorder instead, and its audio does ride up to a cloud to get transcribed, the honest tradeoff for never losing a conversation I needed.&lt;/p&gt;

&lt;p&gt;The output is just more text, dropped into the same inbox as everything else. One from a Friday morning, names changed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;MeetingSubject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;New Feature Kickoff&lt;/span&gt;
&lt;span class="na"&gt;MeetingDate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-05-15T09:00:00&lt;/span&gt;
&lt;span class="na"&gt;Attendees&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ivan, Dana Holt, Marco Ruiz&lt;/span&gt;
&lt;span class="na"&gt;MeetingType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sync&lt;/span&gt;

&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;00&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;00&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;12&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="na"&gt;Dana-Holt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;So the whole feature, end to end. Can we have it live Monday morning?&lt;/span&gt;
&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;00&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;01&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;47&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="na"&gt;Marco-Ruiz&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Monday's a little tight, but yeah, should be fine.&lt;/span&gt;
&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;00&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;02&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;39&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="na"&gt;Ivan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Let's get that on the record.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That transcript is real in shape and, let's say, aspirational in content. Nobody has ever shipped a whole feature between a Friday kickoff and a Monday launch, and I've stopped expecting the meeting to admit it. The pipeline has no such hangups. It files the promise, links "live Monday morning" to Marco, and waits. A few Mondays later I can pull up the exact second optimism met a calendar. Remembering what everyone agreed to before they forget is one of the more useful things a setup like this does.&lt;/p&gt;

&lt;p&gt;It's held together with tape in places. It's Windows-only because of how it grabs system audio, and it wants a decent GPU. But it runs every day, and the recordings stay mine.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What finally made it work wasn't a clever prompt. It was boring plumbing nobody bothers to demo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The lesson worth stealing: don't pay a model to do a regex's job
&lt;/h2&gt;

&lt;p&gt;If you take one thing from this, take this. My first version had the AI do everything: parse email headers, match names to people, score which messages mattered, group threads, spot duplicates. It worked, sort of. It was also slow, expensive, and weirdly inconsistent from one run to the next.&lt;/p&gt;

&lt;p&gt;Then it clicked. A language model does not need to read a &lt;code&gt;From:&lt;/code&gt; line. Parsing that line is string manipulation, and a small Python function does it perfectly, every time, for free. So I moved all the deterministic work into scripts and left the model only the part it's good at: reading a messy thread and telling me what matters.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Let a script do it&lt;/th&gt;
&lt;th&gt;Let the model do it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Parse headers, strip signatures&lt;/td&gt;
&lt;td&gt;Read a messy thread and tell me what matters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resolve names and emails to people&lt;/td&gt;
&lt;td&gt;Pull the real action items out of the language&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Score relevance by rules, dedupe&lt;/td&gt;
&lt;td&gt;Judge whether a borderline message is a big deal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write files, mask private details&lt;/td&gt;
&lt;td&gt;Write the one-line summary I'll actually read&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The result was faster, cheaper, and steadier, because the unpredictable component only touches the unpredictable problem.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The rule that transfers to any AI project: hand the model the fuzzy, judgment-heavy part, and let plain code do everything else. Most "AI is too expensive" and "AI is too flaky" complaints are really that one mistake in disguise, paying a language model to do a regex's job.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The same idea splits the model's own work in two: a cheap model for volume, a smart one for judgment. The bulk work, like summarizing an email or a transcript, runs on a fast cheap model. The handful of jobs that need real judgment, like a weekly review or one-on-one prep, go to the strongest one. Most tokens run cheap, and the expensive brain only shows up when the writing has to be good, which keeps the daily cost around the price of a coffee.&lt;/p&gt;

&lt;p&gt;There's a privacy dividend too, with an honest limit. Before the model reads an email, a script swaps email addresses, phone numbers, IPs, and anything else that scans as private in the body for tokens, and keeps the real values in a local map the AI never sees. It lowers what gets sent rather than removing it: the headers and the meeting transcripts still go through. The useful part is that the deterministic layer is also where I get to decide what the model is allowed to see in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  I decide what it pays attention to
&lt;/h2&gt;

&lt;p&gt;The system only does the work I point it at. I get far too much email to turn all of it into notes, and trying would only bury the handful of things that matter. So I don't process the whole inbox. I point the real work at what I actually need to walk into prepared: a one-on-one, the weekly meeting, a workshop, a project or a person I'm tracking. I control what goes in and what I ask for back. And whatever comes back has to be a scan layer, never a wall of text. The morning briefing takes two minutes to read, and every line links to the full note if I want to dig in. The notes point to people and projects, which point back. I'm not building a novel I'll never reread. I'm building an index I can skim, then drill into when something catches my eye.&lt;/p&gt;

&lt;p&gt;Here is what lands in the daily note each morning, names changed. Two minutes to read, and every line is a link into the full note behind it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Friday, May 15&lt;/span&gt;

&lt;span class="gu"&gt;## Meetings today (1)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; New Feature Kickoff with [[Dana-Holt]] and [[Marco-Ruiz]]; agreed to target a Monday go-live. → [[2026-05-15-new-feature-kickoff|note]]

&lt;span class="gu"&gt;## Key emails&lt;/span&gt;
| | Topic | Summary | Source |
|-|-------|---------|--------|
| &lt;span class="gs"&gt;**!**&lt;/span&gt; | Launch checklist | [[Dana-Holt]] wants the go/no-go criteria locked before Monday; two items still open. | [[2026-05-15-email-launch-checklist|note]] |

&lt;span class="gu"&gt;## Decisions made&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Target Monday, May 18 for the feature go-live.

&lt;span class="gu"&gt;## Action items&lt;/span&gt;
&lt;span class="gs"&gt;**Mine**&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**!**&lt;/span&gt; Send the rollback plan to [[Marco-Ruiz]] before end of day → [[2026-05-15-new-feature-kickoff|Source]]

&lt;span class="gs"&gt;**Waiting on others**&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**!**&lt;/span&gt; [[Marco-Ruiz]] confirm the build is feature-complete → [[2026-05-15-new-feature-kickoff|Source]]
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**!**&lt;/span&gt; [[Dana-Holt]] sign off on the go/no-go criteria → [[2026-05-15-email-launch-checklist|Source]]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What this won't do
&lt;/h2&gt;

&lt;p&gt;Let me be honest about what this is: a personal system, not a product. It took months of nights-and-weekends iteration, and it's tuned to exactly one person's job. The meeting recorder is Windows-only and needs an NVIDIA GPU. I'm not packaging that recorder up to hand out, at least not yet. It's an approach more than a product, and nothing in it is exotic enough to stop you building your own. Speaker identification is good with three or four voices and gets confused in a crowd. Drop the whole thing into your own role and you'd spend a while reshaping the rules before it fit.&lt;/p&gt;

&lt;p&gt;None of that bothers me, because I wasn't trying to start a company. This was me testing how far one person could get with off-the-shelf parts. The answer was further than I expected, and now I've got a connector nobody was selling.&lt;/p&gt;

&lt;h2&gt;
  
  
  The moat was never the model
&lt;/h2&gt;

&lt;p&gt;The vendors will close this gap. A year or two from now the official connectors will exist, the policies will catch up, and some of what I built will look quaint. I'm fine with that. The second brain is a folder of plain text, so when a better connector shows up I just point it at the same files and keep everything I've already gathered. Waiting would have meant another year of an AI that couldn't see my job, when the data problem was solvable right now with tools I already had.&lt;/p&gt;

&lt;p&gt;That's the part worth carrying out of here, and it's bigger than my vault. The intelligence is already here, cheap and getting better on its own schedule. What's missing is almost always the pipe between that intelligence and your actual work. Build the pipe, even out of plain text files and a scheduled task, and you stop waiting for permission to have the thing from the demo.&lt;/p&gt;

&lt;p&gt;I tinker with things like this for myself, the same way I &lt;a href="https://dev.to/blog/ways-of-working/four-days-one-person-redesign"&gt;built this site solo with Claude Code&lt;/a&gt;. The model was never the hard part. The plumbing was.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this goes next
&lt;/h2&gt;

&lt;p&gt;This post is the overview. I'll take the individual pieces apart in follow-ups and link them here as they land:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Capture without an API&lt;/strong&gt;: pulling email and calendar out of a corporate mailbox into the local &lt;code&gt;00-Inbox&lt;/code&gt; folder, with Power Automate and a scheduled task.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private transcription&lt;/strong&gt;: how I turn meeting audio into text on my own GPU, with nothing uploaded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Script-first&lt;/strong&gt;: why the deterministic work runs as plain Python and the model only does the part it's good at.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The skills&lt;/strong&gt;: how one command a day is wired together as Claude Code skills and rules.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>obsidian</category>
      <category>ai</category>
      <category>productivity</category>
      <category>claude</category>
    </item>
  </channel>
</rss>
