<?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: FounderPrompts</title>
    <description>The latest articles on DEV Community by FounderPrompts (@founderprompts).</description>
    <link>https://dev.to/founderprompts</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%2F3959316%2F81486dd6-dfa5-4f9d-b854-03f30cb5f8fe.png</url>
      <title>DEV Community: FounderPrompts</title>
      <link>https://dev.to/founderprompts</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/founderprompts"/>
    <language>en</language>
    <item>
      <title>Making SVG social-media templates rebrandable in 6 lines with CSS classes</title>
      <dc:creator>FounderPrompts</dc:creator>
      <pubDate>Mon, 01 Jun 2026 04:32:45 +0000</pubDate>
      <link>https://dev.to/founderprompts/making-svg-social-media-templates-rebrandable-in-6-lines-with-css-classes-4hfe</link>
      <guid>https://dev.to/founderprompts/making-svg-social-media-templates-rebrandable-in-6-lines-with-css-classes-4hfe</guid>
      <description>&lt;p&gt;Ko-fi: &lt;a href="https://ko-fi.com/s/45e7f1ce3e" rel="noopener noreferrer"&gt;https://ko-fi.com/s/45e7f1ce3e&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I just shipped a pack of 28 social-media templates (square posts, vertical stories, a carousel) and made one deliberate engineering decision: each template is a plain &lt;code&gt;.svg&lt;/code&gt; whose entire color scheme lives in a single &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; block. Rebranding all 28 files means editing six hex values. The technique works for any SVG you want a non-designer to recolor.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with "editable" templates
&lt;/h2&gt;

&lt;p&gt;Most packs ship flattened PNGs, or &lt;code&gt;.canva&lt;/code&gt; links you can only edit inside one tool. Want to change the brand color? You're hunting through every layer in every file. And AI image generators give you something that looks fine once but has zero consistency across a set.&lt;/p&gt;

&lt;h2&gt;
  
  
  Color tokens, but in SVG
&lt;/h2&gt;

&lt;p&gt;SVG supports an internal &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; with CSS classes. So instead of &lt;code&gt;fill="#FF6B5C"&lt;/code&gt; scattered across hundreds of nodes, every shape references a semantic class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;style&amp;gt;
  .bg      { fill: #FFF6F0; }  /* fondo */
  .accent  { fill: #FF6B5C; }  /* color principal */
  .accent2 { fill: #FFB23E; }  /* secundario */
  .ink     { fill: #2B2B36; }  /* titulares */
  .muted   { fill: #8A8A99; }  /* texto apoyo */
  .onacc   { fill: #FFFFFF; }  /* texto sobre acento */
  text     { font-family: 'Poppins','Inter',sans-serif; }
&amp;lt;/style&amp;gt;
...
&amp;lt;rect class="bg" .../&amp;gt;
&amp;lt;circle class="accent" .../&amp;gt;
&amp;lt;text class="ink"&amp;gt;Hazlo con miedo, pero hazlo.&amp;lt;/text&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change &lt;code&gt;.accent&lt;/code&gt; once and every button, badge and blob in the file updates. Because the class names are identical across all 28 files, the same six-line swap rebrands the whole pack. I ship two alternate palettes as ready-to-paste blocks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep text as text
&lt;/h2&gt;

&lt;p&gt;The other rule: never outline the type. Every headline is a real &lt;code&gt;&amp;lt;text&amp;gt;&lt;/code&gt;/&lt;code&gt;&amp;lt;tspan&amp;gt;&lt;/code&gt; node, so the buyer edits copy by changing the string — and it stays editable in Canva (Pro import), Figma, Inkscape or Illustrator. Fonts are Google Fonts (Poppins / Inter / Caveat, OFL) referenced with &lt;code&gt;@import&lt;/code&gt; so a renderer loads them correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rendering to PNG
&lt;/h2&gt;

&lt;p&gt;For the "ready to post" PNG that sits next to each SVG, I render with Playwright: load the SVG into a Chromium page that &lt;code&gt;@import&lt;/code&gt;s the fonts, await &lt;code&gt;document.fonts.ready&lt;/code&gt;, screenshot at the exact size (1080×1080 for posts, 1080×1920 for stories). Same pipeline gives pixel-exact output at any size.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;The copy is all in Spanish — the pack targets Spanish-speaking small businesses and creators, an audience underserved by the English-first template world. But the SVG-as-design-system technique is language-agnostic; steal it for your own brand kit.&lt;/p&gt;

&lt;p&gt;If you want the finished pack (28 templates, SVG + PNG, the two extra palettes, a usage guide), it's $1 on Ko-fi: &lt;a href="https://ko-fi.com/s/45e7f1ce3e" rel="noopener noreferrer"&gt;https://ko-fi.com/s/45e7f1ce3e&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How do you keep a set of graphics on-brand — design tokens, a Figma library, something else?&lt;/p&gt;

</description>
      <category>svg</category>
      <category>css</category>
      <category>design</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I built 6 AI app boilerplates that actually compile (RAG, lead scoring, support triage, resume parser, Slack bot, web scraper)</title>
      <dc:creator>FounderPrompts</dc:creator>
      <pubDate>Mon, 01 Jun 2026 03:39:42 +0000</pubDate>
      <link>https://dev.to/founderprompts/i-built-6-ai-app-boilerplates-that-actually-compile-rag-lead-scoring-support-triage-resume-4h7h</link>
      <guid>https://dev.to/founderprompts/i-built-6-ai-app-boilerplates-that-actually-compile-rag-lead-scoring-support-triage-resume-4h7h</guid>
      <description>&lt;p&gt;Ko-fi: &lt;a href="https://ko-fi.com/s/7296aa7d89" rel="noopener noreferrer"&gt;https://ko-fi.com/s/7296aa7d89&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every time I need to prototype an AI feature, I go looking for a clean starting point. Ninety percent of the time, what I find is a Medium article with 40 lines of Python that imports three packages I have to guess the version of, calls &lt;code&gt;openai.ChatCompletion.create&lt;/code&gt; (the old API), and has no error handling. I run it, it breaks, I spend an hour debugging the wrong thing.&lt;/p&gt;

&lt;p&gt;So I built the versions I actually want to start from.&lt;/p&gt;

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

&lt;p&gt;Six complete AI app repos — TypeScript and Python, all using the Anthropic SDK:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;rag-pdf-chat&lt;/strong&gt; — Upload a PDF, chunk it with token-aware splitting, embed it, store in a vector store (in-memory by default, Pinecone via env), and chat with the document. The answers include citations back to source chunks, so you can verify the model isn't hallucinating. It's Next.js 14 app-router, API routes only, with a minimal UI page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;lead-scoring-api&lt;/strong&gt; — &lt;code&gt;POST /score&lt;/code&gt; with a lead JSON payload, get back &lt;code&gt;{ score: 0-100, reasons: string[], tier }&lt;/code&gt;. Weights are configurable (JSON file or env vars). Fires a webhook when score crosses a threshold, so you can pipe hot leads straight into your CRM or notification system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;support-triage-agent&lt;/strong&gt; — A FastAPI webhook that receives a support ticket and classifies it (&lt;code&gt;{ category: bug|billing|howto|feature, priority: P0-P3, confidence }&lt;/code&gt;). When confidence is above a threshold it drafts a reply; when it's below, it escalates to a human. No LangChain — just the Anthropic SDK and Pydantic v2 models throughout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;resume-parser&lt;/strong&gt; — &lt;code&gt;POST /parse&lt;/code&gt; with a PDF or DOCX file, get back a structured JSON validated by a Pydantic schema: contact info, skills array, experience array (with dates, company, role, bullets), education array. Uses &lt;code&gt;pypdf&lt;/code&gt; and &lt;code&gt;python-docx&lt;/code&gt; for text extraction. Documented OCR fallback note for scanned-image PDFs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;slack-ai-bot&lt;/strong&gt; — &lt;code&gt;app_mention&lt;/code&gt; events reply with a Claude-generated response using the last N messages of the channel as context, so replies are coherent with the conversation. &lt;code&gt;/summarize&lt;/code&gt; slash command summarizes a thread. Persists per-thread conversation history in an in-memory store (pluggable interface).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;web-scraper-llm&lt;/strong&gt; — &lt;code&gt;POST /scrape&lt;/code&gt; with &lt;code&gt;{ url, schema }&lt;/code&gt; where schema is a JSON shape describing what you want extracted. The app fetches the page (rotating User-Agent pool), cleans the HTML to text, passes it to Claude, and returns data matching your schema. Local-fixture mode so tests don't hit the network.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing that makes them actually useful: offline tests
&lt;/h2&gt;

&lt;p&gt;Every app has a test suite that runs without an API key or any network access. The Anthropic client is injected via a factory function — tests swap in a fake. Pinecone, Slack, and HTTP are all mocked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app                   tests   result
──────────────────────────────────────
rag-pdf-chat          19      ✓ passed
lead-scoring-api      14      ✓ passed
support-triage-agent  12      ✓ passed
resume-parser          4      ✓ passed
slack-ai-bot           5      ✓ passed
web-scraper-llm        9      ✓ passed
──────────────────────────────────────
Total                 63      all green
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I say "it builds clean" I mean: &lt;code&gt;npm install &amp;amp;&amp;amp; npm run build &amp;amp;&amp;amp; npm test&lt;/code&gt; goes green on a fresh clone, and &lt;code&gt;pip install -r requirements.txt &amp;amp;&amp;amp; pytest&lt;/code&gt; goes green too. No secret environment variables required for CI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters more than you'd think
&lt;/h2&gt;

&lt;p&gt;The reason AI-generated code is often useless in practice isn't that the logic is wrong — it's that it's missing the boring parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No lockfile, so &lt;code&gt;npm install&lt;/code&gt; resolves different versions on your machine&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;.env.example&lt;/code&gt;, so you don't know what to set&lt;/li&gt;
&lt;li&gt;No retry logic, so one 429 from the LLM crashes the process&lt;/li&gt;
&lt;li&gt;No error handling, so you get an unhandled exception instead of a &lt;code&gt;{ error: "..." }&lt;/code&gt; response&lt;/li&gt;
&lt;li&gt;No tests, so you have no way to verify your changes don't break the happy path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These apps have all of that. Not because it's impressive — because it's what makes the difference between "I pasted this and it worked" and "I spent a day debugging before giving up."&lt;/p&gt;

&lt;h2&gt;
  
  
  Shared conventions and the prompts library
&lt;/h2&gt;

&lt;p&gt;All six apps follow the same conventions: TypeScript apps use Vitest, ESM, strict mode, and Zod for input validation. Python apps use pytest and httpx for the test client. Every server exposes &lt;code&gt;GET /health&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The prompt templates live in &lt;code&gt;apps/_shared/prompts/&lt;/code&gt; — one Markdown file per app. The apps load them at runtime, so you can tune a prompt without touching application code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost estimates
&lt;/h2&gt;

&lt;p&gt;Lead scoring and resume parsing are cheap — those run on &lt;code&gt;claude-haiku-4-5&lt;/code&gt; and cost under $1 for 1,000 requests. RAG chat and web scraping run on &lt;code&gt;claude-sonnet-4-6&lt;/code&gt; for quality and cost more. Full estimates (1k/10k/100k requests) are in &lt;code&gt;COSTS.md&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;All six apps are in a single zip. If you want to start building on one of these patterns instead of from scratch: &lt;a href="https://ko-fi.com/s/7296aa7d89" rel="noopener noreferrer"&gt;https://ko-fi.com/s/7296aa7d89&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>python</category>
      <category>programming</category>
    </item>
    <item>
      <title>12 Postgres schemas every B2B SaaS re-implements (and gets wrong the first time)</title>
      <dc:creator>FounderPrompts</dc:creator>
      <pubDate>Sun, 31 May 2026 03:55:36 +0000</pubDate>
      <link>https://dev.to/founderprompts/12-postgres-schemas-every-b2b-saas-re-implements-and-gets-wrong-the-first-time-3hjk</link>
      <guid>https://dev.to/founderprompts/12-postgres-schemas-every-b2b-saas-re-implements-and-gets-wrong-the-first-time-3hjk</guid>
      <description>&lt;p&gt;Ko-fi: &lt;a href="https://ko-fi.com/s/006956d6b5" rel="noopener noreferrer"&gt;https://ko-fi.com/s/006956d6b5&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every B2B SaaS ends up needing the same dozen pieces in its data layer: multi-tenancy, roles and permissions, an audit log, a billing mirror, a job queue, outbound webhooks, an events table for analytics. And almost every team builds each one twice — because the first version compiles, ships, and then quietly breaks at scale.&lt;/p&gt;

&lt;p&gt;I wrote up the failure modes I keep seeing (and the Postgres 16 patterns that fix them).&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-tenancy: the forgotten &lt;code&gt;WHERE tenant_id&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Pooled multi-tenancy — one database, a &lt;code&gt;tenant_id&lt;/code&gt; column on every table — is the model that actually stays operable past a few hundred tenants. The danger is a single query that forgets &lt;code&gt;WHERE tenant_id = $1&lt;/code&gt; and leaks another tenant's data.&lt;/p&gt;

&lt;p&gt;Row-Level Security turns that from a breach into a non-event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="n"&gt;ENABLE&lt;/span&gt; &lt;span class="k"&gt;ROW&lt;/span&gt; &lt;span class="k"&gt;LEVEL&lt;/span&gt; &lt;span class="k"&gt;SECURITY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;POLICY&lt;/span&gt; &lt;span class="n"&gt;tenant_isolation&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt;
  &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tenant_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current_setting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'app.current_tenant'&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set &lt;code&gt;app.current_tenant&lt;/code&gt; once per request and every query is constrained automatically. The matching index leads with &lt;code&gt;tenant_id&lt;/code&gt;: &lt;code&gt;(tenant_id, created_at DESC)&lt;/code&gt; — because in a pooled model every hot query filters by tenant first.&lt;/p&gt;

&lt;h2&gt;
  
  
  The job queue race nobody tests for
&lt;/h2&gt;

&lt;p&gt;The naive "SELECT a pending job, then UPDATE it to running" has a race: two workers grab the same row. Under load you run the same job twice. The fix is one statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'running'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'pending'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;scheduled_at&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scheduled_at&lt;/span&gt;
  &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;SKIP&lt;/span&gt; &lt;span class="n"&gt;LOCKED&lt;/span&gt;
  &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;RETURNING&lt;/span&gt; &lt;span class="o"&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;code&gt;FOR UPDATE SKIP LOCKED&lt;/code&gt; lets N workers pull disjoint rows with zero collisions — a real queue, no Redis, backed by a partial index on &lt;code&gt;(priority DESC, scheduled_at) WHERE status = 'pending'&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The audit log that's unqueryable at 50M rows
&lt;/h2&gt;

&lt;p&gt;An audit trail grows forever. If it's a plain table, retention means a slow &lt;code&gt;DELETE&lt;/code&gt; and endless vacuum. Declarative monthly partitioning makes retention a &lt;code&gt;DROP TABLE&lt;/code&gt; of last year's partition — instant. The tax you accept: a partitioned table's primary key must include the partition key, so lookups need &lt;code&gt;(id, created_at)&lt;/code&gt;, not &lt;code&gt;id&lt;/code&gt; alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stripe webhook that double-charges
&lt;/h2&gt;

&lt;p&gt;Stripe delivers events at-least-once and sometimes out of order. A handler that just applies each event will eventually apply a stale &lt;code&gt;subscription.updated&lt;/code&gt; after a newer one. The mirror needs a &lt;code&gt;stripe_event_id UNIQUE&lt;/code&gt; for idempotency and a &lt;code&gt;last_event_at&lt;/code&gt; guard so an older event can't overwrite a newer state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why an AI's first attempt isn't this
&lt;/h2&gt;

&lt;p&gt;Ask a model for "a multi-tenant schema with RBAC and an audit log" and you get something plausible — and missing the partial unique index that lets you re-create a soft-deleted row, the BRIN index that keeps the events table from bloating, the deny-wins resolution in the permission check, the idempotency key on the webhook. Those are the parts you only add after the second rewrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pack
&lt;/h2&gt;

&lt;p&gt;I packaged the iterated versions: 12 Postgres 16 schemas, each with &lt;code&gt;schema.sql&lt;/code&gt; + Drizzle + Prisma, up/down migrations, seed data, and a &lt;code&gt;queries.md&lt;/code&gt; with EXPLAIN notes — plus an ARCHITECTURE.md showing how the 12 layer into one backend and a DECISIONS.md for the cross-schema trade-offs. Every schema + seed is verified to load on a clean Postgres instance; core PG16 only, no extensions.&lt;/p&gt;

&lt;p&gt;If you're starting a B2B SaaS and want the "I'll just adapt these and move on" reference: &lt;a href="https://ko-fi.com/s/006956d6b5" rel="noopener noreferrer"&gt;https://ko-fi.com/s/006956d6b5&lt;/a&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>sql</category>
      <category>database</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I Turned My Cursor + Claude Code Setup Into 12 Reusable Files</title>
      <dc:creator>FounderPrompts</dc:creator>
      <pubDate>Sun, 31 May 2026 02:59:39 +0000</pubDate>
      <link>https://dev.to/founderprompts/i-turned-my-cursor-claude-code-setup-into-12-reusable-files-1127</link>
      <guid>https://dev.to/founderprompts/i-turned-my-cursor-claude-code-setup-into-12-reusable-files-1127</guid>
      <description>&lt;p&gt;Ko-fi: &lt;a href="https://ko-fi.com/s/fdb0e60135" rel="noopener noreferrer"&gt;https://ko-fi.com/s/fdb0e60135&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most Cursor and Claude Code configurations degrade to the same thing: you paste a vague system prompt, you coach the AI repeatedly through the same patterns every project, and the output is inconsistent because nothing is actually encoded anywhere permanent.&lt;/p&gt;

&lt;p&gt;I spent a few weeks turning the patterns that work — the ones I kept re-explaining from scratch — into actual files. Proper format. The format Cursor and Claude Code expect. Drop them in, and they run.&lt;/p&gt;

&lt;p&gt;Here is what I built and why each artifact required real iteration to get right.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code Reviewer Subagent
&lt;/h2&gt;

&lt;p&gt;Claude Code supports subagents: &lt;code&gt;.md&lt;/code&gt; files in &lt;code&gt;.claude/agents/&lt;/code&gt; with YAML frontmatter that defines a model, a description (which controls auto-delegation), and a system prompt. When you say "review my code," Claude Code reads the description field of every agent and delegates to the right one.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;code-reviewer&lt;/code&gt; agent's system prompt structures the output into four categories — correctness bugs, security issues (OWASP-tagged), data-loss risks, and performance problems — and requires a severity table and a merge verdict. That last part matters: without it, every review ends ambiguously and you're making the call yourself anyway.&lt;/p&gt;

&lt;p&gt;Getting the OWASP tagging right took several iterations. The model would skip it when the issue wasn't an obvious injection or auth bypass. The fix was a constraint in the system prompt: every security finding must include an OWASP Top 10 reference or explicitly note "not mapped" with a reason. Now it does it consistently.&lt;/p&gt;

&lt;p&gt;The other three subagents follow the same pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;test-generator&lt;/strong&gt; — detects your test framework (Vitest, Jest, pytest), reads your existing conventions, and produces zero-stub tests with real assertions. The hard part was getting it to produce runnable tests rather than placeholder structures. The system prompt now explicitly bans &lt;code&gt;// TODO&lt;/code&gt; and &lt;code&gt;pass&lt;/code&gt; in test bodies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;dependency-auditor&lt;/strong&gt; — runs native audit tools when available (&lt;code&gt;npm audit&lt;/code&gt;, &lt;code&gt;pip-audit&lt;/code&gt;), falls back to manual analysis with named CVE IDs. Naming real CVEs was the iteration — the model would otherwise produce vague "potential vulnerability" notes that are useless for prioritization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;migration-runner&lt;/strong&gt; — the one that required the most work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Migration Runner: Safe SQL Against a Live Database
&lt;/h2&gt;

&lt;p&gt;Writing SQL migrations that are safe to run against a production database is not a one-shot problem. The failure mode is a migration that works fine on a test database and blocks the primary lock on a table with 50 million rows in production.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;migration-runner&lt;/code&gt; subagent analyzes lock risks per operation before generating SQL. An &lt;code&gt;ADD COLUMN NOT NULL&lt;/code&gt; with a default blocks the table for the duration of the migration on older PostgreSQL versions. The safe version is three operations: add the column as nullable, backfill in batches, then add the constraint separately.&lt;/p&gt;

&lt;p&gt;The system prompt encodes this specifically. When the agent sees an &lt;code&gt;ADD COLUMN NOT NULL&lt;/code&gt;, it rewrites it into the three-step sequence automatically and explains why. Each migration also gets a working &lt;code&gt;down&lt;/code&gt; block — not a comment saying "reverse this manually," an actual rollback script.&lt;/p&gt;

&lt;p&gt;That rewrite logic took about an hour of iteration: getting the batch size right, handling the constraint name consistently, making the down block correct for each of the three steps independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lint Hook That Blocks via Exit 2
&lt;/h2&gt;

&lt;p&gt;Claude Code hooks run shell scripts at specific points in the tool lifecycle. A &lt;code&gt;PreToolUse&lt;/code&gt; hook fires before any &lt;code&gt;Edit&lt;/code&gt;, &lt;code&gt;Write&lt;/code&gt;, or &lt;code&gt;MultiEdit&lt;/code&gt; call. If the hook exits with code 2, Claude Code blocks the edit.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;pre-commit-lint&lt;/code&gt; hook does exactly this: it runs ESLint on JS/TS files, Ruff on Python files, or cargo clippy on Rust files, parses the output, and exits 2 if there are problems. Claude Code sees the lint errors in the hook output and fixes them before retrying the edit.&lt;/p&gt;

&lt;p&gt;The non-obvious part: the hook needs to handle the case where no linter is installed without blocking the edit. An uninstalled linter should exit 0 silently, not exit 2 and break everything. The &lt;code&gt;lint.sh&lt;/code&gt; script checks for each linter before calling it and skips cleanly if it's absent.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;post-edit-test&lt;/code&gt; hook is the mirror: it fires after each edit, runs related tests (Vitest, Jest, or pytest, detected from the project), and prints &lt;code&gt;[test-hook] PASS&lt;/code&gt; / &lt;code&gt;FAIL&lt;/code&gt; / &lt;code&gt;SKIP&lt;/code&gt;. It never exits 2 — it informs without blocking.&lt;/p&gt;

&lt;p&gt;Wiring hooks requires merging a JSON snippet into &lt;code&gt;.claude/settings.json&lt;/code&gt;. The pack includes both the shell scripts and the JSON snippets with the exact merge result documented.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Skills: Protocols, Not Instructions
&lt;/h2&gt;

&lt;p&gt;Skills are a newer Claude Code primitive: folders in &lt;code&gt;.claude/skills/&lt;/code&gt; with a &lt;code&gt;SKILL.md&lt;/code&gt; that Claude Code reads when it auto-delegates based on the skill's description.&lt;/p&gt;

&lt;p&gt;The two skills in the pack encode protocols rather than instructions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;long-running-tasks&lt;/strong&gt; — a checkpoint-based execution protocol. Before starting any multi-step task, write &lt;code&gt;_state.json&lt;/code&gt; with the step list and current index. After each step completes, update the state file. On failure or restart, read the state file and resume from the last completed step. The skill includes a &lt;code&gt;state.template.json&lt;/code&gt; and a &lt;code&gt;_progress.log&lt;/code&gt; format. This is how you run a multi-hour pipeline through Claude Code without losing progress on a crash.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;api-integration&lt;/strong&gt; — a production-grade API integration protocol covering: credential lookup from environment variables (never hardcoded), connection timeouts, exponential backoff with jitter, &lt;code&gt;Retry-After&lt;/code&gt; header handling, idempotency keys on POST requests, circuit breaker state, and webhook signature verification. Every integration Claude Code writes when this skill is active follows the full protocol.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What This Is and Is Not
&lt;/h2&gt;

&lt;p&gt;These are functional files. They work because they're built to the format Cursor and Claude Code expect — the frontmatter, the glob patterns, the hook lifecycle, the skill directory structure. Dropping them in is not a configuration step; it is the installation.&lt;/p&gt;

&lt;p&gt;Each file represents 30–60 minutes of real iteration: writing the first version, running it against real inputs, finding the failure modes, and encoding the fixes as constraints. You are skipping that work.&lt;/p&gt;

&lt;p&gt;This is not a prompt pack. Prompts are instructions you give the model at conversation start. These files modify how the toolchain itself behaves — which agent runs on which request, which rules attach to which files, which hooks fire at which points in the edit lifecycle.&lt;/p&gt;

&lt;p&gt;The pack is 12 files: 4 subagents, 4 Cursor rules, 2 hook scripts + 2 JSON snippets, 2 skill folders.&lt;/p&gt;

&lt;p&gt;If you use Cursor or Claude Code daily and want the setup to behave like a senior engineer without coaching it from scratch on every project: &lt;a href="https://ko-fi.com/s/fdb0e60135" rel="noopener noreferrer"&gt;https://ko-fi.com/s/fdb0e60135&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>devtools</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
