<?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: Mateusz Dembek</title>
    <description>The latest articles on Forem by Mateusz Dembek (@dembsky).</description>
    <link>https://forem.com/dembsky</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%2F3784771%2F8d0fcd4c-c81e-4d89-aff4-76132dea0ef9.jpg</url>
      <title>Forem: Mateusz Dembek</title>
      <link>https://forem.com/dembsky</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/dembsky"/>
    <language>en</language>
    <item>
      <title>CLAUDE.md - how to set up project instructions for Claude Code</title>
      <dc:creator>Mateusz Dembek</dc:creator>
      <pubDate>Sat, 28 Feb 2026 11:18:12 +0000</pubDate>
      <link>https://forem.com/dembsky/claudemd-how-to-set-up-project-instructions-for-claude-code-5gna</link>
      <guid>https://forem.com/dembsky/claudemd-how-to-set-up-project-instructions-for-claude-code-5gna</guid>
      <description>&lt;p&gt;My CLAUDE.md is 216 lines long. It references 13 separate rule files. It has a section called "How to Work With Mateusz" that includes gems like "Do not soften truth" and "When he says change X, change exactly X. Not Y. Not X and also improved Z. Just X."&lt;/p&gt;

&lt;p&gt;I also have a file called &lt;code&gt;lessons-learned.md&lt;/code&gt; where Claude automatically logs every mistake it makes. There are 20+ entries. One of them is about a hover color where Claude guessed &lt;code&gt;#404040&lt;/code&gt; instead of looking up the actual token. The real value was &lt;code&gt;#737373&lt;/code&gt;. Darker instead of lighter. Claude was too lazy to check, and I was too trusting to notice until it looked wrong.&lt;/p&gt;

&lt;p&gt;This is what happens when you take CLAUDE.md seriously. You end up building a relationship with a tool that forgets you exist every time you close the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  The week the internet said to delete it
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://arxiv.org/html/2602.11988" rel="noopener noreferrer"&gt;study from ETH Zurich&lt;/a&gt; tested four coding agents on hundreds of real tasks. With instruction files and without.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/init&lt;/code&gt; makes things worse. Agents using auto-generated files solved fewer problems and cost 20% more. The generated content just repeated what the agent could already see by reading the code. You're paying Claude to read the same information twice.&lt;/p&gt;

&lt;p&gt;Human-written files improved results by about 4%, but also cost more tokens. That 4% only happens if the file contains things Claude wouldn't figure out on its own.&lt;/p&gt;

&lt;p&gt;Theo Browne &lt;a href="https://x.com/theo/status/2025900730847232409" rel="noopener noreferrer"&gt;tweeted&lt;/a&gt; "delete your CLAUDE.md" to half a million people. Addy Osmani &lt;a href="https://addyosmani.com/blog/agents-md/" rel="noopener noreferrer"&gt;wrote&lt;/a&gt; that you should stop using &lt;code&gt;/init&lt;/code&gt;. Reddit piled on. For about 48 hours, instruction files were dead.&lt;/p&gt;

&lt;p&gt;Nobody talked about what the study tested. They ran auto-generated boilerplate against coding benchmarks on unfamiliar projects. No lessons-learned file. No workflow rules. No "scan every hover state before writing CSS" born from Claude guessing a color wrong. They tested the worst version of these files and found it doesn't work. That's what happens when you write too much, too vague, and for problems you don't have yet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vercel.com/blog/agents-md-outperforms-skills-in-our-agent-evals" rel="noopener noreferrer"&gt;Vercel tested the opposite&lt;/a&gt;. They put documentation for APIs that didn't exist during training into an instruction file. Pass rate went from 53% to 100%. When the file contains things the agent can't discover on its own, it works.&lt;/p&gt;

&lt;p&gt;If your CLAUDE.md repeats what's in &lt;code&gt;package.json&lt;/code&gt; and your folder structure, delete it. If it contains your preferences, your conventions, and the mistakes Claude made last week, keep it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is CLAUDE.md
&lt;/h2&gt;

&lt;p&gt;It's a text file in your project. Claude reads it at the start of every session. Whatever you write there becomes part of how it thinks about your code.&lt;/p&gt;

&lt;p&gt;I have terrible memory. Names, conversations, where I left things. So when I say Claude forgets everything the moment you close the terminal, I mean I get it on a personal level. The difference is I can drink coffee. Claude just gets a fresh CLAUDE.md.&lt;/p&gt;

&lt;p&gt;Without it, every session starts with Claude poking around your files trying to figure out what's going on. With it, Claude starts with the right context: what matters, what to avoid, how you want things done. Instead of six rounds of "no, not like that," you get two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to put it
&lt;/h2&gt;

&lt;p&gt;I didn't know this at first, but Claude reads instructions from two places.&lt;/p&gt;

&lt;p&gt;There's a personal file at &lt;code&gt;~/.claude/CLAUDE.md&lt;/code&gt;. Whatever you put there applies to every project you open. I use mine for coding philosophy, commit conventions, which AI models to use for which tasks. The stuff that's true regardless of what I'm building. Things like "no emojis in code" and "always use conventional commits" go here because I want them everywhere.&lt;/p&gt;

&lt;p&gt;Then there's the project file. Drop a &lt;code&gt;CLAUDE.md&lt;/code&gt; in your main project folder (or inside &lt;code&gt;.claude/&lt;/code&gt; if you want a cleaner root). This one is for the team. Commit it. Everyone who opens the project gets the same instructions. This blog has one that says "Lighthouse target: 100/100/100/100. 99 is not acceptable." My other projects have completely different rules.&lt;/p&gt;

&lt;p&gt;The two layers stack. Personal preferences load first, project rules load on top. If they disagree, the project wins. Your preference is yours, but the project has the final word.&lt;/p&gt;

&lt;p&gt;There's also &lt;code&gt;CLAUDE.local.md&lt;/code&gt; for stuff you don't want to commit. Local dev URLs, test credentials, personal shortcuts. It gets gitignored automatically.&lt;/p&gt;

&lt;p&gt;I discovered the layering by accident. I kept copy-pasting the same rules into every project's CLAUDE.md. Then I realized the personal file existed and moved all the shared stuff there. Now I write my preferences once and they follow me everywhere. Project-specific stuff stays project-specific. No more duplicate rules drifting out of sync.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to put in it
&lt;/h2&gt;

&lt;p&gt;Start with whatever you keep repeating. If you've told Claude the same thing three sessions in a row, that thing belongs in CLAUDE.md.&lt;/p&gt;

&lt;p&gt;The fastest way is just telling Claude what to remember:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;add to CLAUDE.md that this is an Astro 5 blog with MDX,
Tailwind CSS 4, deployed on Vercel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude writes the entry for you. You don't have to think about formatting or structure. Next time you correct something:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;add to CLAUDE.md: always use conventional commits.
feat: for features, fix: for bugs, refactor: for cleanup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when you catch Claude doing something wrong:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;add a rule to CLAUDE.md: no emojis in code or content.
also add: Lighthouse target is 100/100/100/100, 99 is not acceptable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file writes itself from your corrections. Every time Claude does something you don't like, you tell it to remember. After a few sessions, you have a CLAUDE.md that reflects how you work. Not a template you copied from someone's blog post.&lt;/p&gt;

&lt;p&gt;You can also put in architecture notes, folder structure, how things connect. I'd wait. Add those when Claude gets confused about where something lives. If it never gets confused, you saved yourself the context cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let Claude write the first draft
&lt;/h2&gt;

&lt;p&gt;If you want a starting point, Claude Code has a command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It scans your project and generates a CLAUDE.md based on what it finds. As I mentioned above, the ETH Zurich study found this actually makes things worse. &lt;code&gt;/init&lt;/code&gt; writes down things Claude can already see by reading your code. Your folder structure, your tech stack, your build commands. Claude reads the same facts twice and you pay for both.&lt;/p&gt;

&lt;p&gt;If you use &lt;code&gt;/init&lt;/code&gt;, gut it. Delete everything Claude can figure out on its own. What survives is probably two paragraphs. Or skip it entirely and build the file from corrections, like I described above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Splitting rules into separate files
&lt;/h2&gt;

&lt;p&gt;One file works fine until it doesn't. My CLAUDE.md hit maybe 400 lines and I noticed Claude was ignoring stuff near the bottom. Rules I'd written carefully were having zero effect. So I told it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;split CLAUDE.md into separate rule files under .claude/rules/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My personal &lt;code&gt;~/.claude/rules/&lt;/code&gt; directory has 13 files. There's &lt;code&gt;bulletproof.md&lt;/code&gt; with platform-specific coding rules for React, React Native, and Swift. There's &lt;code&gt;security.md&lt;/code&gt; that blocks Claude from committing API keys (I wrote about &lt;a href="https://ctrlship.dev/blog/security-checks-before-you-ship" rel="noopener noreferrer"&gt;why that matters&lt;/a&gt;). There's &lt;code&gt;anti-drift.md&lt;/code&gt; that prevents &lt;a href="https://ctrlship.dev/blog/what-are-claude-code-agents" rel="noopener noreferrer"&gt;AI agents&lt;/a&gt; from going off-script during complex tasks. And there's &lt;code&gt;lessons-learned.md&lt;/code&gt;, which is basically a diary of Claude's failures.&lt;/p&gt;

&lt;p&gt;You don't need 13 files. You probably need two or three. But knowing you &lt;em&gt;can&lt;/em&gt; split things up means you won't end up with one massive file that's impossible to maintain.&lt;/p&gt;

&lt;p&gt;Claude doesn't read like you do. It pays the most attention to the beginning and end of its context, and the least to the middle. Long files mean rules get lost in that dead zone. Shorter, focused files mean every rule lands.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lessons-learned file
&lt;/h2&gt;

&lt;p&gt;I have a file called &lt;code&gt;lessons-learned.md&lt;/code&gt; with a simple rule at the top: every time Claude makes a mistake, it has to log it. Automatically. No asking. The format is strict: date, project, what went wrong, why, what was fixed, and a new rule to prevent it from happening again.&lt;/p&gt;

&lt;p&gt;A real entry from the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;### [2026-02-19] NEVER guess CSS values - scan tokens from Design System
- Project: Shift
- Error: Hover on Button/Secondary set to #404040 (darker than default #525252).
  Correct hover is #737373 (lighter). I guessed instead of reading tokens
- Cause: Laziness. Didn't query Figma API for hover variant. Made up #404040
- Fix: Read tokens. Applied correct values
- Rule: BEFORE writing ANY CSS value for a DS component, scan ALL states.
  NEVER guess hover/focus/active values. ALWAYS scan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude literally wrote "Cause: Laziness" about itself. And that new rule at the bottom? It gets checked before every coding session. So the next time Claude works with design tokens, it reads that entry first and knows not to guess.&lt;/p&gt;

&lt;p&gt;After 20 entries, I review them. Patterns that keep repeating get promoted to permanent rules in &lt;code&gt;bulletproof.md&lt;/code&gt;. The rest stay as a reference. So it gets better over time. Not on its own. Because I built the system that forces it. The downside? All those rules and self-checks mean Claude burns through tokens the way I burn through creatine. Every session starts with it reading its own diary before it even looks at my code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other things worth knowing
&lt;/h2&gt;

&lt;p&gt;There's a feature where rules only apply to specific files. You put a &lt;code&gt;paths&lt;/code&gt; field in the frontmatter and the rule kicks in only when Claude touches matching files. I don't use it much, but if your frontend and backend have different conventions, it's useful. CLAUDE.md also supports &lt;code&gt;@&lt;/code&gt; imports for pulling content from other files into your instructions. The &lt;a href="https://docs.anthropic.com/en/docs/claude-code/memory" rel="noopener noreferrer"&gt;official docs&lt;/a&gt; cover the syntax for both.&lt;/p&gt;

&lt;p&gt;Auto memory is separate. You can just say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;remember that we use pnpm, not npm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude saves it to a memory file that loads every session. For this blog, Claude's auto memory includes things like the background color change from pure black to &lt;code&gt;#121212&lt;/code&gt;, why it was changed, and that every heading uses a specific CSS variable. Small things I'd otherwise repeat every session. Run &lt;code&gt;/memory&lt;/code&gt; to see what it's saved and fix anything wrong or outdated.&lt;/p&gt;

&lt;p&gt;All of this eats context. Everything in CLAUDE.md, every rule file, every memory entry takes up space in the same window Claude needs for reading your code, thinking, and generating a response. My setup loads around 200 lines of CLAUDE.md plus 13 rule files. That's a lot of tokens burned before Claude even looks at what I'm building. On a Max plan, I notice it. Sessions with large files get slower. Complex refactors hit the ceiling faster.&lt;/p&gt;

&lt;p&gt;A hundred well-chosen lines beat three hundred generic ones. If a rule doesn't save you time at least once a week, it probably doesn't belong there. I've pruned mine twice already and I'll do it again. The &lt;a href="https://docs.anthropic.com/en/docs/claude-code/memory" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; covers the technical details if you want the full picture.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mistakes I made
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Too much too soon.&lt;/strong&gt; My first CLAUDE.md was 400 lines of everything I could think of. Claude read all of it but most of it was noise. Whatever you keep repeating to Claude belongs in CLAUDE.md. Everything else was wasting context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Too vague.&lt;/strong&gt; "Use 2-space indentation, no semicolons, prefer const over let" is useful. "Write clean code" is not. Be specific or don't bother.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never updating it.&lt;/strong&gt; Projects change. CLAUDE.md doesn't update itself. And then you sit there debugging rules you wrote two months ago wondering why Claude keeps doing something you stopped wanting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Putting secrets in it.&lt;/strong&gt; Don't. No API keys, no passwords, no connection strings. CLAUDE.md is a text file. If you commit it (and you should for team projects), everyone sees it. Use environment variables for secrets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Writing rules for problems I didn't have yet.&lt;/strong&gt; I added error handling rules before I'd encountered a single error. Accessibility rules before I had a single clickable button on the page. Those rules sat there eating context for weeks before they became relevant. Write rules when you need them, not when you think you might need them someday. This is the hardest one to follow because it feels productive to write rules. It's not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start small, then let it grow from pain
&lt;/h2&gt;

&lt;p&gt;Create a CLAUDE.md in your main project folder. Put in your stack, your main commands, and three conventions you care about.&lt;/p&gt;

&lt;p&gt;Then pay attention. The next time you catch yourself explaining the same thing to Claude twice, stop explaining and write it down instead. Your CLAUDE.md grows from actual pain, not from anticipating pain.&lt;/p&gt;

&lt;p&gt;My setup is extreme. Yours doesn't have to be. But somewhere between "no CLAUDE.md" and "13 rule files with a self-improvement loop," there's a version that fits how you work. You'll find it by using Claude, getting annoyed, and writing one more rule.&lt;/p&gt;

&lt;p&gt;The annoying part is that it works. Claude with good instructions wastes less of your time. And the only way to write them is to watch Claude guess a hover color wrong and think, I should have told it.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>vibecoding</category>
      <category>beginners</category>
    </item>
    <item>
      <title>5 security checks before you ship your vibe-coded app</title>
      <dc:creator>Mateusz Dembek</dc:creator>
      <pubDate>Sun, 22 Feb 2026 08:56:17 +0000</pubDate>
      <link>https://forem.com/dembsky/5-security-checks-before-you-ship-your-vibe-coded-app-29m6</link>
      <guid>https://forem.com/dembsky/5-security-checks-before-you-ship-your-vibe-coded-app-29m6</guid>
      <description>&lt;p&gt;I pushed an API key (a secret password that lets your app connect to outside services) to a &lt;a href="https://ctrlship.dev/blog/github-for-vibe-coders" rel="noopener noreferrer"&gt;repo&lt;/a&gt;. My own key. In the actual code, sitting there in plain text for anyone on the project to see. Lucky for me, the repo was private. I only caught it because I have this habit of skimming every change after pushing it (watching myself do it, I'm starting to think it might be ADHD), even though I barely understand what I'm looking at. That day, something looked off. A long string of characters in a file that shouldn't have one.&lt;/p&gt;

&lt;p&gt;I asked Claude: "Is that my API key in the code?" It was. Claude put it there when I told it to connect to the service. I said "connect," it connected. It also pasted the key right into a file instead of putting it somewhere safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened to Moltbook
&lt;/h2&gt;

&lt;p&gt;In January 2026, Matt Schlicht launched Moltbook, an AI social network. His tweet got over 500,000 views.&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.amazonaws.com%2Fuploads%2Farticles%2Fr6eo9287tpmf3n9uc8jk.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr6eo9287tpmf3n9uc8jk.png" alt="Tweet by Matt Schlicht announcing Moltbook - 538K views, days later Wiz found the database wide open" width="800" height="326"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;538K views. Days later, Wiz found the database wide open.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then Wiz &lt;a href="https://www.wiz.io/blog/exposed-moltbook-database-reveals-millions-of-api-keys" rel="noopener noreferrer"&gt;dug into it&lt;/a&gt;. 1.5 million authentication tokens. 35,000 email addresses. Private messages between agents. All of it open. The whole thing came down to one database setting that was never turned on. AI built the app, but nobody asked it to secure the app.&lt;/p&gt;

&lt;p&gt;I read that and thought: that could have been me. I build apps the same way Matt does. I say "build this" and AI builds it. I've never once said "and make sure nobody can break in."&lt;/p&gt;
&lt;h2&gt;
  
  
  Why this keeps happening
&lt;/h2&gt;

&lt;p&gt;Researchers tested a bunch of AI-generated apps. &lt;a href="https://arxiv.org/html/2512.03262v1" rel="noopener noreferrer"&gt;61% worked correctly. 10.5% were actually secure.&lt;/a&gt; Every app I've built was in that first group. I'm pretty sure none of them made it to the second.&lt;/p&gt;

&lt;p&gt;The code is optimized for one thing: does it work? It's like hiring a contractor who builds you a beautiful house with no lock on the front door. Nobody asked for locks, so there are none.&lt;/p&gt;
&lt;h2&gt;
  
  
  The five checks
&lt;/h2&gt;

&lt;p&gt;So I read a bunch of security reports. I understood maybe 40% of them. Here's what I got. Each one comes with a prompt you can paste straight into your AI tool. The prompts contain some technical terms. You don't need to understand them. Your AI does.&lt;/p&gt;
&lt;h3&gt;
  
  
  Your database is wide open
&lt;/h3&gt;

&lt;p&gt;Supabase has a setting called Row Level Security (RLS). Firebase has its own version called Security Rules. Both control who can see what data. Both are almost never configured properly in AI-generated code.&lt;/p&gt;

&lt;p&gt;Moltbook was the loudest example, but not the only one. Someone &lt;a href="https://escape.tech/state-of-security-of-vibe-coded-apps" rel="noopener noreferrer"&gt;audited 5,600 vibe-coded apps&lt;/a&gt;. Over 2,000 security holes. Database access controls were a recurring theme. Not a bug. The default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Check every table in my Supabase database. Enable Row Level
Security on all of them. For each table, create policies that
only allow users to read and modify their own data. Show me
what you changed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Secrets in your source code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.gitguardian.com/state-of-secrets-sprawl-report-2025" rel="noopener noreferrer"&gt;23.8 million secrets were leaked&lt;/a&gt; on public GitHub repositories in 2024. And they don't get cleaned up: 70% of secrets leaked back in 2022 were still active two years later. People push keys, forget about them, and the keys just sit there. For years.&lt;/p&gt;

&lt;p&gt;API keys, database passwords, service URLs. They end up directly in your code files because that's the fastest path to working code. AI takes the fastest path every time.&lt;/p&gt;

&lt;p&gt;The fix is a file called &lt;code&gt;.env&lt;/code&gt;. It stores your secrets separately from your code, as something called environment variables. Another file called &lt;code&gt;.gitignore&lt;/code&gt; tells GitHub to never upload &lt;code&gt;.env&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Move all API keys, passwords, and database URLs out of the
code and into a .env file. Add .env to .gitignore. Make sure
no secrets appear anywhere in the code. Use environment
variables everywhere instead.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're already &lt;a href="https://ctrlship.dev/blog/github-for-vibe-coders" rel="noopener noreferrer"&gt;using GitHub&lt;/a&gt;, check that Secret Scanning and Push Protection are turned on in your repository settings. Public repos have them enabled by default and they're free. Private repos need a paid plan (GitHub Secret Protection, $19/month per active committer). And even when they're on, they only catch secrets that follow recognizable patterns, like keys from well-known services. A random API key with no recognizable pattern? Goes right through. The &lt;code&gt;.env&lt;/code&gt; setup above is still the real fix.&lt;/p&gt;

&lt;h3&gt;
  
  
  The login page that looks right but works wrong
&lt;/h3&gt;

&lt;p&gt;The login page looks professional. The problem is what happens behind the form.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.wiz.io/blog/common-security-risks-in-vibe-coded-apps" rel="noopener noreferrer"&gt;Wiz dug into a bunch of vibe-coded apps&lt;/a&gt; and the findings were bleak. Password checks running in the browser instead of the server, meaning anyone who knows how to open developer tools can see the logic. "Stay logged in" handled by a simple flag in the browser that says "this user is logged in," which anyone can flip in seconds. That's it. That's the security.&lt;/p&gt;

&lt;p&gt;The fix here isn't a prompt. It's a decision. Don't let AI build your login system from scratch. Use a library that thousands of developers have already tested. Supabase Auth, NextAuth, Clerk, Firebase Auth. Pick one. (If you're not sure which fits your project, I covered &lt;a href="https://ctrlship.dev/blog/how-to-pick-the-right-tech-for-your-project" rel="noopener noreferrer"&gt;how to choose your tech stack&lt;/a&gt; in an earlier post.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do not build custom authentication. Use [Supabase Auth / NextAuth /
Clerk / Firebase Auth] for all login, signup, and session management.
Make sure every page that requires login redirects unauthenticated
users. Make sure passwords are never stored in plain text.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The package that doesn't exist
&lt;/h3&gt;

&lt;p&gt;Sometimes your code references packages. These are pre-built chunks of code written by other developers that your project borrows. Except some of the ones AI suggests don't exist. The names are fabricated. AI just made them up.&lt;/p&gt;

&lt;p&gt;Here's where it gets weird. Attackers watch for these fake names. Then they register them on npm, the main directory where JavaScript packages live, and fill them with malicious code. Your project tries to install a package AI invented, and it downloads something an attacker planted there yesterday. There's a name for it: &lt;a href="https://www.csoonline.com/article/3961304/ai-hallucinations-lead-to-new-cyber-threat-slopsquatting.html" rel="noopener noreferrer"&gt;"slopsquatting."&lt;/a&gt; I did not make that up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://socket.dev/blog/slopsquatting-how-ai-hallucinations-are-fueling-a-new-class-of-supply-chain-attacks" rel="noopener noreferrer"&gt;Up to 21.7% of packages AI references don't exist&lt;/a&gt; (less with commercial models, more with open-source ones). And 58% of those fake names show up consistently across multiple sessions, which makes them predictable targets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;List every npm package this project uses. For each one, verify
it exists on npmjs.com and has more than 1,000 weekly downloads.
Remove any package that doesn't exist or isn't actively
maintained. Remove any package that isn't actually used in the
code.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your project is on GitHub, turn on Dependabot. It watches the packages you use and alerts you when any of them have known security problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Your forms trust everyone
&lt;/h3&gt;

&lt;p&gt;Every form in your app accepts text. Someone can type a script instead of their name. If your app doesn't clean the input first, it just runs it. This is called cross-site scripting. The code you get back &lt;a href="https://www.veracode.com/blog/genai-code-security-report/" rel="noopener noreferrer"&gt;fails to prevent it roughly 87% of the time&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add input validation and sanitization to every form and user
input in the project. No user input should ever be inserted
directly into database queries, HTML output, or system
commands. Use parameterized queries for all database
operations. Sanitize HTML output to prevent script injection.
Show me every change.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to actually run these checks
&lt;/h2&gt;

&lt;p&gt;You don't need to remember five separate prompts. Here's one you can paste at the start of any new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before writing any code, set up these security basics:

1. Create a .env file for all secrets (API keys, database URLs,
   passwords). Add .env to .gitignore. Never hardcode secrets
   in source files.

2. If this project uses Supabase or Firebase, enable Row Level
   Security on every table. Create policies so users can only
   access their own data.

3. Use an established auth library for all login and signup.
   No custom authentication code. Make sure every protected
   page checks for a valid session.

4. Validate and sanitize all user inputs. No raw input in
   database queries or HTML output. Use parameterized queries.

5. Before installing any package, verify it exists on npmjs.com
   and is actively maintained. Do not install packages with
   fewer than 1,000 weekly downloads unless I approve it.

Follow these rules for the entire project. If any of them
conflict with a feature request, tell me before proceeding.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you already have a live project, paste this instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Audit this entire project for security issues. Check for:
hardcoded secrets in any file, .env files not in .gitignore,
Row Level Security disabled on any database table, user inputs
used without validation or sanitization, authentication
bypasses, admin routes without auth checks, and unused or
suspicious packages. Create a numbered list of every issue
with the file name and a specific fix for each.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And before you push anything live, ask AI to review its own work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Act as a security reviewer. Go through every file in this
project and check for: hardcoded secrets, missing input
validation, unprotected routes, Row Level Security disabled,
plain text passwords, unnecessary packages, and any other
security issue. List every problem you find with the file
name and what needs to change.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I use &lt;a href="https://context7.com" rel="noopener noreferrer"&gt;Context7&lt;/a&gt; (by Upstash, thanks Doug!) for code review. It's a plugin that gives AI access to current documentation for whatever tools your project uses, instead of whatever was in the training data months ago. Works with Cursor, Claude Code, and Windsurf. Free.&lt;/p&gt;

&lt;p&gt;If your project is on GitHub, go to Settings and enable Dependabot (free on all repos). If your repo is public, also turn on Secret Scanning and Push Protection (also free). For private repos, these two require a paid GitHub plan. They won't fix existing problems, but they'll catch new ones before they go public.&lt;/p&gt;

&lt;p&gt;That API key I pushed to my repo? Claude fixed it in two minutes once I asked. The problem wasn't the fix. It was that I didn't know to ask. Now I do. Now you do too.&lt;/p&gt;

</description>
      <category>security</category>
      <category>vibecoding</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to install and run Claude Code in VS Code</title>
      <dc:creator>Mateusz Dembek</dc:creator>
      <pubDate>Sun, 22 Feb 2026 08:33:54 +0000</pubDate>
      <link>https://forem.com/dembsky/how-to-install-and-run-claude-code-in-vs-code-3ll4</link>
      <guid>https://forem.com/dembsky/how-to-install-and-run-claude-code-in-vs-code-3ll4</guid>
      <description>&lt;p&gt;On November 24th one of my dev friends (hey Maciej!) told me I could run Claude Code in VS Code's terminal. I had no idea. Shame on me I guess. Since then I've been building all the things I always wanted but never had a developer for.&lt;/p&gt;

&lt;p&gt;Let me show you how to start using it. Install to first prompt in under 5 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Open VS Code and the terminal
&lt;/h2&gt;

&lt;p&gt;Open your project folder in VS Code. If you don't have a project yet, create an empty folder somewhere and open that.&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.amazonaws.com%2Fuploads%2Farticles%2F5drfvsxfqiykwc70eoip.webp" 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.amazonaws.com%2Fuploads%2Farticles%2F5drfvsxfqiykwc70eoip.webp" alt="VS Code welcome screen with a list of keyboard shortcuts" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;VS Code after opening a project. Ignore the shortcuts for now.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Pull up the terminal. Top menu: Terminal &amp;gt; New Terminal. Or just hit &lt;code&gt;Ctrl+&lt;/code&gt;`.&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.amazonaws.com%2Fuploads%2Farticles%2Fxf72tks3e3ttbtgpffnp.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Fxf72tks3e3ttbtgpffnp.webp" alt="VS Code with terminal panel open at the bottom" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;This is where you'll type commands and talk to Claude.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This terminal at the bottom is where everything happens. All the commands below go here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Install Claude Code
&lt;/h2&gt;

&lt;p&gt;Same terminal. One command, nothing else to install first.&lt;/p&gt;

&lt;p&gt;On Mac or Linux:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
curl -fsSL https://claude.ai/install.sh | bash&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;On Windows (PowerShell):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;powershell&lt;br&gt;
irm https://claude.ai/install.ps1 | iex&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You'll see a few lines of output. When it stops and you get your cursor back, you're good. Close and reopen VS Code so the terminal picks up the new command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Launch it
&lt;/h2&gt;

&lt;p&gt;Same terminal. Type &lt;code&gt;claude&lt;/code&gt; and hit Enter.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
claude&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;First time you run it, there's a quick setup. Takes about a minute.&lt;/p&gt;

&lt;p&gt;It asks you to pick a color theme:&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.amazonaws.com%2Fuploads%2Farticles%2F8qm95yz5u3leyqnyb4hk.webp" 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.amazonaws.com%2Fuploads%2Farticles%2F8qm95yz5u3leyqnyb4hk.webp" alt="Claude Code first launch showing theme selection with Dark mode highlighted" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Theme selection on first launch. Dark mode is the only correct answer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next up: how you want to log in. You need a Claude Pro, Max, or API account.&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.amazonaws.com%2Fuploads%2Farticles%2Feygt7ud851c5rhs43ay5.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Feygt7ud851c5rhs43ay5.webp" alt="Claude Code login method selection showing three options: subscription, API, and third-party" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;If you're paying for Claude Pro or Max, pick option 1.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It opens a browser window where you authorize the connection:&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.amazonaws.com%2Fuploads%2Farticles%2Fiybbajxddigt391d1e95.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Fiybbajxddigt391d1e95.webp" alt="Claude.ai authorization page in the browser asking to connect Claude Code to your account" width="800" height="725"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Click Authorize and switch back to VS Code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Back in VS Code, it confirms you're logged in:&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.amazonaws.com%2Fuploads%2Farticles%2Fzgl9q949fbpypj64cnya.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Fzgl9q949fbpypj64cnya.webp" alt="Claude Code terminal showing a login successful message" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Login confirmed. Almost there.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next it shows security notes. Read them or don't, then press Enter.&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.amazonaws.com%2Fuploads%2Farticles%2F91ylx1k54ivhhmbzdusd.webp" 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.amazonaws.com%2Fuploads%2Farticles%2F91ylx1k54ivhhmbzdusd.webp" alt="Claude Code security notes about reviewing AI responses and code injection risks" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Standard disclaimer. Press Enter to continue.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now it wants to know about terminal settings.&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.amazonaws.com%2Fuploads%2Farticles%2Fqqsb59uhj1uzglthklen.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Fqqsb59uhj1uzglthklen.webp" alt="Claude Code asking whether to use recommended terminal settings" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Say yes. This makes Shift+Enter work for new lines, which you'll use constantly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Last step: it checks if you trust the project folder.&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.amazonaws.com%2Fuploads%2Farticles%2Ferzmjcq4edzj8sxu32tf.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Ferzmjcq4edzj8sxu32tf.webp" alt="Claude Code workspace safety check asking if you trust this folder" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Your own project? Trust it. Random folder from the internet? Maybe don't.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's it. You're in. The whole setup takes about a minute once you've done it before.&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.amazonaws.com%2Fuploads%2Farticles%2Fk92ufth9qgcdbfshhn13.webp" 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.amazonaws.com%2Fuploads%2Farticles%2Fk92ufth9qgcdbfshhn13.webp" alt="Claude Code fully set up and ready for input in VS Code terminal" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Claude Code ready to go. Type what you want to build and hit Enter.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When things break
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;"command not found"&lt;/strong&gt; - Close VS Code, reopen, try again. Works embarrassingly often.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Permission errors&lt;/strong&gt; - Paste the error into any AI chat and ask for help. That's what I do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Login issues&lt;/strong&gt; - The login opens in your browser. If it's not working, clear browser cookies, try incognito, log in again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anything else&lt;/strong&gt; - Screenshot the error and paste it into any AI chat. Ask it to help. No shame in that. I do the same thing every day. My entire debugging strategy is asking AI to fix the AI setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Install Claude Code. Type &lt;code&gt;claude&lt;/code&gt; in your project folder. When something breaks, screenshot it and ask AI.&lt;/p&gt;

&lt;p&gt;If I figured this out as a designer who's never written a line of code, you'll be fine.&lt;/p&gt;

&lt;p&gt;Oh, and for those of us who appreciate readable font sizes: &lt;code&gt;Cmd+=&lt;/code&gt; (or &lt;code&gt;Ctrl+=&lt;/code&gt; on Windows) zooms in the whole VS Code window, terminal included. Killer feature.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>vscode</category>
      <category>vibecoding</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
