<?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>Forem: Luke Hanner</title>
    <description>The latest articles on Forem by Luke Hanner (@lukehanner).</description>
    <link>https://forem.com/lukehanner</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3651056%2F47fdf078-7908-4693-be72-380addb430de.jpeg</url>
      <title>Forem: Luke Hanner</title>
      <link>https://forem.com/lukehanner</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/lukehanner"/>
    <language>en</language>
    <item>
      <title>SpecifyThat is live — and it makes context files, not specs</title>
      <dc:creator>Luke Hanner</dc:creator>
      <pubDate>Sat, 28 Feb 2026 12:00:00 +0000</pubDate>
      <link>https://forem.com/lukehanner/specifythat-is-live-and-it-makes-context-files-not-specs-313k</link>
      <guid>https://forem.com/lukehanner/specifythat-is-live-and-it-makes-context-files-not-specs-313k</guid>
      <description>&lt;p&gt;The last update on SpecifyThat said it just needed to work again. It works. It's live. But the more important thing that shipped isn't the status badge — it's clarity about what the tool actually makes. The clearest signal was trying to explain it to someone. A spec is a document you write before you build. A context file is a document your AI reads while it builds. One sits in Notion. The other gets used. I'd been calling it the wrong thing for months. ## What shipped - **The output is a context file, not a spec.** SpecifyThat now generates the file your AI coding tool reads at the start of every session — stack, architecture, conventions, non-goals — not a document for humans. That distinction matters. Specs sit in Notion. Context files get used. - **v2 flow: describe once, AI fills the rest.** You write a sentence or two about your project. AI works through all 13 questions behind the scenes and comes back with a full review screen. Everything pre-filled. You adjust what's wrong — most people change nothing — then generate. - **Works for every major AI coding tool.** Cursor, Claude Code, Windsurf, Bolt, Copilot. Each one expects its context in a different file at a different path. The generated file works for all of them. &lt;a href="https://specifythat.com/how-it-works" rel="noopener noreferrer"&gt;/how-it-works&lt;/a&gt; now explains where to drop it for each. - **Multi-part support.** If your project has distinct modules or you want to spec a backend and frontend separately, you can run the flow multiple times in one session and get a file per part. Those four changes shipped in the same push. They felt like separate things right up until I noticed they were all solving the same problem: getting from vague idea to a file your AI can actually use, with as little friction as possible. ## Why The old framing — "generate a spec" — was wrong. Nobody pastes a spec into Cursor. They paste context. Renaming it didn't change the output much, but it changed who the tool is for and how it gets used. Solo builders who want to start coding in ten minutes, not write documentation. The v2 flow exists because the original interview — question by question, one at a time — felt like homework. The point was always to skip the planning step, not to disguise it as a chat. I built this for me first. I skip the planning step too. Now I don't have to. ## What's next Three things in the backlog, in rough priority order: **AI confidence review.** After generating, a second AI pass reads the spec against the original project description and surfaces 1-3 gaps — things that are ambiguous, missing, or contradictory. You answer them or skip. The idea came from manually asking a model "review this until you're 95% sure you could build it" — that step should be automatic. Planning to use Claude Opus 4.6 for this, which is built for exactly this kind of sustained critical review. **UI/design constraints.** One new question in the interview: "Any UI/design constraints AI should know?" — mobile-first vs desktop, dark mode requirement, component library already in use. Not a brand exercise; just enough context so AI doesn't make arbitrary stack choices. Users with a &lt;code&gt;brand.md&lt;/code&gt; can skip it. **Brand discovery mode.** A separate interview mode that generates a &lt;code&gt;brand.md&lt;/code&gt; instead of a context file — vibe, tone, personality, emotional direction. Parked until there's user signal that people want it, but the interview pattern fits naturally. None of those ship before there's signal. The rate limit data will tell me when to add billing. Usage will tell me what to build next. The issues are parked until then. Right now it just needs to be used.&lt;/p&gt;

</description>
      <category>specifythat</category>
    </item>
    <item>
      <title>Why every tool I build will be local-first</title>
      <dc:creator>Luke Hanner</dc:creator>
      <pubDate>Fri, 27 Feb 2026 12:00:00 +0000</pubDate>
      <link>https://forem.com/lukehanner/why-every-tool-i-build-will-be-local-first-502g</link>
      <guid>https://forem.com/lukehanner/why-every-tool-i-build-will-be-local-first-502g</guid>
      <description>&lt;p&gt;I spent last night writing a manifesto that boils down to one line: **Your prompts never leave your device.** Not a promise. An architectural guarantee. The app runs on your machine. API calls go directly from your browser to the AI provider. My server only touches the billing layer. I never see your content. Here's why this matters and why I think the current model is broken. ## The gatekeeping problem Want to try an AI tool? Create an account. Verify your email. Pick a plan. Enter your credit card. Now you're locked in — paying $15/month whether you use it once or a hundred times, getting promo emails you never asked for, with your prompts stored on servers you can't audit. That's not a product. That's a trap dressed up as a product. ## What I'm building instead **No accounts.** You open the tool and use it. No username, no password, no "sign up to continue." **No subscriptions.** Pay for what you use, when you use it. Prepaid credits. Top up when you want, stop when you want. Like a transit card — not a gym membership. **No data harvesting.** I don't store, log, or mine your inputs. My backend handles credit deduction. The content of what you're asking bypasses me entirely. ## The business model I'm a utility reseller. AI providers are the power generators — I buy wholesale tokens, sell retail. The margin between what I pay per token and what I charge is the business. Simple, transparent, scales with usage. Free trial on launch. Rate-limited, using my API key, so you can experience the tool with zero friction. When you want more, you buy credits through a one-time Stripe payment. No account created. No subscription initiated. ## Where this goes In five years, on-device inference will handle most everyday AI tasks. The cloud API becomes reserved for heavy lifting. When that happens, "your prompts never leave your device" becomes even more true — and my costs drop because I'm not paying for API calls. The account-per-tool model will feel as outdated as remembering your AOL login. Device-level identity and native payment rails will replace it. I want to be building for that future. Starting now. ## First up: SpecifyThat &lt;a href="https://specifythat.com" rel="noopener noreferrer"&gt;SpecifyThat&lt;/a&gt; is the first tool getting rebuilt with this philosophy. Today it's a server-side app where my API routes see every prompt. The rebuild flips that: API routes become thin proxies that forward to OpenAI without logging or storing what you send. My server never writes your prompt to a database or a log. Same tool, fundamentally different architecture. More on that soon.&lt;/p&gt;

</description>
      <category>philosophy</category>
    </item>
    <item>
      <title>SpecifyThat — built for me, found by others</title>
      <dc:creator>Luke Hanner</dc:creator>
      <pubDate>Thu, 26 Feb 2026 12:00:00 +0000</pubDate>
      <link>https://forem.com/lukehanner/specifythat-built-for-me-found-by-others-50co</link>
      <guid>https://forem.com/lukehanner/specifythat-built-for-me-found-by-others-50co</guid>
      <description>&lt;p&gt;Before Modryn Studio existed, I shipped &lt;a href="https://specifythat.com" rel="noopener noreferrer"&gt;SpecifyThat&lt;/a&gt;. The problem: I kept starting projects with a half-formed idea and wasting the first hour of a build session figuring out what I was actually trying to build. So I built a tool to fix that. Thirteen targeted questions. If you don't know the answer, an AI fills the gap using "top 0.1% thinking" for that decision. At the end, you get a copy-ready spec to paste into Cursor, Copilot, or whatever you build with. I never marketed it. It's not on Google Search Console. But two people found it, signed up for updates, someone starred it, and someone forked it. That's enough signal. It's listed here now as beta. The AI backend is being swapped from Anthropic to OpenAI (cost reasons — a full spec gen costs fractions of a cent on GPT-5 mini). Once that's live, the status flips. The tool has a wish list a mile long. That's a later problem. Right now it just needs to work again.&lt;/p&gt;

</description>
      <category>tools</category>
    </item>
    <item>
      <title>How I set up my Copilot workflow</title>
      <dc:creator>Luke Hanner</dc:creator>
      <pubDate>Thu, 26 Feb 2026 12:00:00 +0000</pubDate>
      <link>https://forem.com/lukehanner/how-i-set-up-my-copilot-workflow-43ah</link>
      <guid>https://forem.com/lukehanner/how-i-set-up-my-copilot-workflow-43ah</guid>
      <description>&lt;p&gt;Every new project I start now gets the same setup: a &lt;code&gt;.github/&lt;/code&gt; folder that turns VS Code into a disciplined co-pilot rather than an eager yes-man. Here's what's in it. **&lt;code&gt;@check&lt;/code&gt;** — a pre-ship agent. Before every push, I type &lt;code&gt;@check&lt;/code&gt; and it reads all recently changed files, hunts for bugs, runs lint, runs a build, and commits any fixes. It never pushes. I review the diff, then push myself. That one habit has caught at least three dumb mistakes that would have gone to production. **&lt;code&gt;/init&lt;/code&gt;** — new project setup. I fill in two files (&lt;code&gt;context.md&lt;/code&gt; and &lt;code&gt;brand.md&lt;/code&gt;) with the product facts and brand rules, then run &lt;code&gt;/init&lt;/code&gt;. Copilot reads both and fills in the always-on instructions file that lives in every session. Takes 5 minutes instead of 20. **&lt;code&gt;/seo&lt;/code&gt;** — pre-launch checklist. Generates &lt;code&gt;sitemap.ts&lt;/code&gt;, &lt;code&gt;robots.ts&lt;/code&gt;, &lt;code&gt;manifest.ts&lt;/code&gt;, and JSON-LD structured data automatically. Audits for missing OG images and character counts. Then walks me through Google Search Console and Bing registration step by step. **&lt;code&gt;src/config/site.ts&lt;/code&gt;** — single source of truth for the site name, URL, description, and brand colors. Change it once and the manifest, JSON-LD, sitemap, and metadata all update on the next build. No sync needed. The whole thing is in a public repo at &lt;a href="https://github.com/modryn-studio/boilerplate" rel="noopener noreferrer"&gt;github.com/modryn-studio/boilerplate&lt;/a&gt;. Copy the &lt;code&gt;.github/&lt;/code&gt; folder into any Next.js project and it works. Built for one-person studios that ship fast and can't afford to forget things.&lt;/p&gt;

</description>
      <category>meta</category>
    </item>
    <item>
      <title>The site is live</title>
      <dc:creator>Luke Hanner</dc:creator>
      <pubDate>Wed, 25 Feb 2026 12:00:00 +0000</pubDate>
      <link>https://forem.com/lukehanner/the-site-is-live-3oi1</link>
      <guid>https://forem.com/lukehanner/the-site-is-live-3oi1</guid>
      <description>&lt;p&gt;Shipped modrynstudio.com today. One page. Dark mode. Email signup. That's it. The plan: detect a rising trend, score it, ship a tool in 48 hours, capture traffic early. Repeat. Every tool gets a page here. Every decision, kill, and lesson gets a log post. That's the deal. First tool in progress: Trend Detector. Follow along.&lt;/p&gt;

</description>
      <category>modrynstudio</category>
    </item>
    <item>
      <title>I Wasted 6 Months Building Products Nobody Wanted. Then I Discovered the Real Problem.</title>
      <dc:creator>Luke Hanner</dc:creator>
      <pubDate>Tue, 16 Dec 2025 17:56:04 +0000</pubDate>
      <link>https://forem.com/lukehanner/i-wasted-6-months-building-products-nobody-wanted-then-i-discovered-the-real-problem-4704</link>
      <guid>https://forem.com/lukehanner/i-wasted-6-months-building-products-nobody-wanted-then-i-discovered-the-real-problem-4704</guid>
      <description>&lt;h2&gt;
  
  
  The Grind (That Led Nowhere)
&lt;/h2&gt;

&lt;p&gt;Six months ago, I was in full builder mode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PropTools&lt;/strong&gt; - A Bootstrap site comparing futures prop firms. Spent months building it. Clean UI. Good data. Launched it.&lt;/p&gt;

&lt;p&gt;Then discovered PropTraderTools already existed. Exact same concept.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Modryn Studio&lt;/strong&gt; - Weeks building a Next.js marketing site for my web development company. TypeScript. Tailwind. Beautiful animations.&lt;/p&gt;

&lt;p&gt;Zero clients.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Client Portal&lt;/strong&gt; - Built an entire customer management system. Authentication. Dashboards. The works.&lt;/p&gt;

&lt;p&gt;Problem? No customers to manage.&lt;/p&gt;

&lt;p&gt;I kept building. Nothing was working.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pivot (That Also Failed)
&lt;/h2&gt;

&lt;p&gt;"Small businesses need websites. I'll build those."&lt;/p&gt;

&lt;p&gt;I created a CLI tool with templates for contractors, restaurants, salons. Could generate a professional site in 2 hours.&lt;/p&gt;

&lt;p&gt;Built a free salon website for a friend. She loved it.&lt;/p&gt;

&lt;p&gt;Perfect. Time to scale.&lt;/p&gt;

&lt;p&gt;Except cold calling isn't my thing. Couldn't sell a single site.&lt;/p&gt;

&lt;p&gt;I was stuck:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Fast at building&lt;/li&gt;
&lt;li&gt;❌ Terrible at selling&lt;/li&gt;
&lt;li&gt;❌ No idea what to build next&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Experiment That Changed Everything
&lt;/h2&gt;

&lt;p&gt;Instead of building another product, I tried something different.&lt;/p&gt;

&lt;p&gt;I asked GPT &amp;amp; Claude: "Give me coding tests. Small projects. I want to know what kind of developer I am."&lt;/p&gt;

&lt;p&gt;I got specs. Real, detailed specifications:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PROJECT: Task Timer CLI

REQUIREMENTS:
- Start/stop timers with task names
- Store data in SQLite
- Export to CSV
- Show daily summaries

CONSTRAINTS:
- No GUI, CLI only
- &amp;lt; 500 lines of code
- Single executable

SUCCESS CRITERIA:
- User can track 3 tasks simultaneously
- Data persists across sessions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I finished it in 23 minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wait, what?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The same type of project that used to take me days.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pattern
&lt;/h2&gt;

&lt;p&gt;I asked for more specs. More projects.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ToDo API: 18 minutes&lt;/li&gt;
&lt;li&gt;Markdown blog generator: 47 minutes
&lt;/li&gt;
&lt;li&gt;URL shortener: 31 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The difference wasn't my coding ability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It was the specs.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When I had a clear specification:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ No analysis paralysis&lt;/li&gt;
&lt;li&gt;✅ No scope creep&lt;/li&gt;
&lt;li&gt;✅ No "wait, what am I building?"&lt;/li&gt;
&lt;li&gt;✅ Just execute&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When I wrote my own specs, I'd spend 2-3 hours staring at blank pages, second-guessing decisions, ending up with vague notes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Problem
&lt;/h2&gt;

&lt;p&gt;I didn't need to learn more frameworks.&lt;br&gt;
I didn't need better design skills.&lt;br&gt;
I didn't need more business ideas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I needed better specs.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But writing good specs myself? That was the hard part.&lt;/p&gt;

&lt;p&gt;So I built a tool to do it for me.&lt;/p&gt;
&lt;h2&gt;
  
  
  Introducing SpecifyThat
&lt;/h2&gt;

&lt;p&gt;A conversational spec generator that asks the 13 critical questions every project needs answered.&lt;/p&gt;
&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;13 Targeted Questions&lt;/strong&gt; - Each maps to a section of a technical spec&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Gap Filling&lt;/strong&gt; - Click "I don't know" for expert suggestions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;10-Minute Specs&lt;/strong&gt; - From vague idea to executable spec&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  The Meta Part
&lt;/h3&gt;

&lt;p&gt;I used Claude to generate a spec for SpecifyThat. Then I built SpecifyThat using that spec.&lt;/p&gt;

&lt;p&gt;The tool generated the specification that built itself.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Tech Stack
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend: Next.js 14 + TypeScript
AI: Claude Sonnet 4 (Anthropic API)
Styling: Tailwind CSS
Deployment: Vercel
Build Time: 2 days
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Key Technical Decisions
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Claude's &lt;code&gt;tool_use&lt;/code&gt; for Structured Outputs
&lt;/h3&gt;

&lt;p&gt;Instead of parsing text responses (which fail ~15% of the time), I used Anthropic's tool definitions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;analyzeProjectTool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Tool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;analyze_project&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Analyze a project description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;input_schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;single&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;multiple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;units&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;claude-sonnet-4-20250514&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;analyzeProjectTool&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;tool_choice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tool&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;analyze_project&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&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;&lt;strong&gt;Result:&lt;/strong&gt; 100% valid JSON responses. Zero parsing failures.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. XML Wrappers Prevent Prompt Injection
&lt;/h3&gt;

&lt;p&gt;User input gets wrapped in XML tags before sending to the AI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buildAnalysisPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Analyze the following project description:

&amp;lt;user_project_description&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
&amp;lt;/user_project_description&amp;gt;

Determine if this is one buildable unit or multiple...`&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 prevents users from manipulating the AI's responses with instructions hidden in their project descriptions.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Gibberish Detection Saves Money
&lt;/h3&gt;

&lt;p&gt;Launch day: Users typed "asdfasdf" and got AI-generated responses.&lt;/p&gt;

&lt;p&gt;Added validation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isGibberishInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Check vowel ratio&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vowels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;aeiou&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/gi&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vowelRatio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vowels&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="nx"&gt;vowelRatio&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.08&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Check for repeated patterns&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;.&lt;/span&gt;&lt;span class="se"&gt;)\1{4,}&lt;/span&gt;&lt;span class="sr"&gt;/&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="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Check for keyboard mashing&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keyboards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;qwertyuiop&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;asdfghjkl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zxcvbnm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;kb&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;keyboards&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kb&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&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="kc"&gt;false&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;h3&gt;
  
  
  4. Multi-Unit Detection
&lt;/h3&gt;

&lt;p&gt;Complex projects get automatically detected and broken down:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AnalysisResult&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;single&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;multiple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;units&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&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;When a user describes something like "a SaaS with auth, billing, and dashboards," the AI detects 3 buildable phases and lets them spec one at a time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; Scope creep kills projects. Breaking them into shippable units increases completion rates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features I Didn't Plan (But Users Needed)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The "I Don't Know" Button
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Insight:&lt;/strong&gt; Developers don't struggle with coding. They struggle with making spec decisions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ideation Mode
&lt;/h3&gt;

&lt;p&gt;Some users clicked "I don't know" on Q2 (project description) because they literally didn't have a clear idea yet.&lt;/p&gt;

&lt;p&gt;Added a 3-step discovery wizard:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What problem frustrates you?&lt;/li&gt;
&lt;li&gt;Who will use this?&lt;/li&gt;
&lt;li&gt;What category? (9 options with icons)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The AI synthesizes these answers into a project description, which the user can edit before proceeding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Even vague ideas become actionable specs.&lt;/p&gt;

&lt;h3&gt;
  
  
  File Upload Support
&lt;/h3&gt;

&lt;p&gt;Users wanted to paste existing docs. Added support for .txt and .md files (up to 10MB).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleFileUpload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;analyzeProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&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;The AI analyzes both the text input AND the attached document together.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Good Specs Are Force Multipliers
&lt;/h3&gt;

&lt;p&gt;With a clear spec, I can build in hours what used to take days.&lt;/p&gt;

&lt;p&gt;The bottleneck isn't coding ability. It's specification clarity.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Users Know When They Don't Know
&lt;/h3&gt;

&lt;p&gt;People struggle with decisions, not execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Build What You Need First
&lt;/h3&gt;

&lt;p&gt;I built SpecifyThat because I needed it. Every feature exists because I ran into that problem myself.&lt;/p&gt;

&lt;p&gt;That's why it works. I'm the target user.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Ship Fast, Iterate Later
&lt;/h3&gt;

&lt;p&gt;2 days from idea to production. Bugs and all.&lt;/p&gt;

&lt;p&gt;Bugs I fixed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gibberish input validation (added after seeing "asdfasdf")&lt;/li&gt;
&lt;li&gt;Back button on multi-unit screen (wasn't clearing state)&lt;/li&gt;
&lt;li&gt;Character counter on Q1&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The 6-Month Lesson
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Old approach:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spend months building&lt;/li&gt;
&lt;li&gt;Launch with no audience&lt;/li&gt;
&lt;li&gt;Wonder why nobody cares&lt;/li&gt;
&lt;li&gt;Repeat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;New approach:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identify YOUR problem&lt;/li&gt;
&lt;li&gt;Build the solution fast&lt;/li&gt;
&lt;li&gt;Ship publicly&lt;/li&gt;
&lt;li&gt;Let the market tell you if it matters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SpecifyThat exists because I wasted 6 months learning this lesson the hard way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SpecifyThat is free, requires no login, and works on mobile.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Try it: &lt;a href="https://specifythat.com" rel="noopener noreferrer"&gt;https://specifythat.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open source: &lt;a href="https://github.com/modryn-studio/specifythat" rel="noopener noreferrer"&gt;https://github.com/modryn-studio/specifythat&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What's your biggest challenge when planning projects?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do you spend more time planning or building? Let me know in the comments.&lt;/p&gt;

</description>
      <category>career</category>
      <category>discuss</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
