Free rules / Ship-safe
Rules that stop the 5 fails vibe-coded apps keep shipping
AI coding agents are fast, but they repeat the same five mistakes. Paste these rules into your project and your agent checks for them every time it writes code. Free, no signup.
- Secrets in the client or in the repo
- Missing security headers
- Weak HTTPS assumptions
- Broken asset and link paths
- Fat client bundles
1. Secrets in the client or in the repo
Agents reach for the quickest working fix: an API key pasted into a component, or an env var renamed with a public prefix so the browser can read it. That key is now in your public bundle, and often in git history too.
- Never put API keys, tokens, database URLs or service-role keys in client-side code, or in any env var with a public prefix (NEXT_PUBLIC_, VITE_, PUBLIC_, EXPO_PUBLIC_, REACT_APP_). Those values are inlined into the browser bundle.
- Only publishable values get a public prefix (analytics IDs, Stripe publishable key, Supabase anon key with RLS on).
- Never commit .env files. Before creating one, make sure .gitignore lists .env, .env.local and .env*.local. Keep a .env.example with placeholder values only.
- Calls that need a secret go through a server route, server action or edge function; the browser only talks to that route.
- If you find a secret in client code or git history, stop and tell me so I can rotate it. Deleting the line is not enough.2. Missing security headers
Frameworks don't send most security headers by default, and agents rarely add them unless asked. Without them, your app can be framed for clickjacking, MIME-sniffed, or leak full URLs in the Referer header.
- Every web app sends these response headers in production:
- Content-Security-Policy: start strict (default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none') and allow only the extra origins the app really uses.
- Strict-Transport-Security: max-age=63072000; includeSubDomains (many hosts, e.g. Vercel, already send HSTS: check before adding a second one).
- X-Content-Type-Options: nosniff
- Referrer-Policy: strict-origin-when-cross-origin
- X-Frame-Options: DENY (older browsers), unless the app must be embedded.
- Set them in one place in the framework or host config (next.config headers(), vercel.json "headers", Netlify _headers), not per page. frame-ancestors only works as a real header, not in a <meta> tag.
- When adding a third-party script, widget or API, add that exact origin to the CSP. Never "fix" a CSP error by removing the CSP or adding *.
- After changing headers, load the app and check the browser console for CSP violations.3. Weak HTTPS assumptions
Code written against localhost tends to keep its http:// URLs and relaxed cookie settings. In production that means mixed-content errors, or session cookies that travel without protection.
- Never hard-code http:// URLs for your own site, APIs or assets. Use https:// or relative URLs, and read the base URL from config.
- Session and auth cookies are Secure, HttpOnly and SameSite=Lax (or Strict).
- Redirect HTTP to HTTPS at the host, and never load scripts, styles or API calls over plain HTTP (mixed content).
- Webhook and OAuth callback URLs are https:// in production.4. Broken asset and link paths
Agents mix relative, root-relative and local file paths, rename routes without updating links, and forget alt text. It all works on their machine and 404s after deploy.
- Reference public assets one consistent way. On a site served from the domain root, use root-relative paths (/images/logo.png). If the app is served from a subfolder (GitHub Pages project sites, itch.io), set the framework's base path (e.g. Vite base: "./") instead of hand-editing URLs.
- Never reference local file system paths (C:\..., /Users/...) or files outside the public folder.
- File names are case-sensitive on most hosts: match the exact case.
- After adding, renaming or removing a route, update every internal link, redirect and the sitemap. No links to routes that don't exist.
- Images always have width and height (or an aspect ratio) and meaningful alt text.5. Fat client bundles
Each "just install this" adds weight, and agents rarely look at bundle size. Slow first loads hurt both users and search rankings.
- Don't import a whole library for one function (lodash, moment, full icon packs). Import the specific module or use the platform (Intl, Array methods, fetch).
- Keep data fetching and heavy logic on the server when the framework supports it (server components, loaders, API routes).
- Lazy-load below-the-fold components, charts, editors and maps.
- Ask before adding a dependency, and say what it adds.
- Before finishing a feature, check the build output for any client chunk that grew a lot and explain why.The whole file
All five sections as one always-on Cursor rule. For Claude Code or AGENTS.md, drop the part between the --- lines.
---
description: Ship-safe rules - secrets, security headers, HTTPS, asset paths, bundle size
alwaysApply: true
---
# Ship-safe rules (always on)
Source: https://agentcartridge.com/rules/ship-safe (free; updated 2026-10-19)
Apply these whenever you touch config, env vars, auth, routes, assets, dependencies or deployment.
## 1. Secrets in the client or in the repo
- Never put API keys, tokens, database URLs or service-role keys in client-side code, or in any env var with a public prefix (NEXT_PUBLIC_, VITE_, PUBLIC_, EXPO_PUBLIC_, REACT_APP_). Those values are inlined into the browser bundle.
- Only publishable values get a public prefix (analytics IDs, Stripe publishable key, Supabase anon key with RLS on).
- Never commit .env files. Before creating one, make sure .gitignore lists .env, .env.local and .env*.local. Keep a .env.example with placeholder values only.
- Calls that need a secret go through a server route, server action or edge function; the browser only talks to that route.
- If you find a secret in client code or git history, stop and tell me so I can rotate it. Deleting the line is not enough.
## 2. Missing security headers
- Every web app sends these response headers in production:
- Content-Security-Policy: start strict (default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none') and allow only the extra origins the app really uses.
- Strict-Transport-Security: max-age=63072000; includeSubDomains (many hosts, e.g. Vercel, already send HSTS: check before adding a second one).
- X-Content-Type-Options: nosniff
- Referrer-Policy: strict-origin-when-cross-origin
- X-Frame-Options: DENY (older browsers), unless the app must be embedded.
- Set them in one place in the framework or host config (next.config headers(), vercel.json "headers", Netlify _headers), not per page. frame-ancestors only works as a real header, not in a <meta> tag.
- When adding a third-party script, widget or API, add that exact origin to the CSP. Never "fix" a CSP error by removing the CSP or adding *.
- After changing headers, load the app and check the browser console for CSP violations.
## 3. Weak HTTPS assumptions
- Never hard-code http:// URLs for your own site, APIs or assets. Use https:// or relative URLs, and read the base URL from config.
- Session and auth cookies are Secure, HttpOnly and SameSite=Lax (or Strict).
- Redirect HTTP to HTTPS at the host, and never load scripts, styles or API calls over plain HTTP (mixed content).
- Webhook and OAuth callback URLs are https:// in production.
## 4. Broken asset and link paths
- Reference public assets one consistent way. On a site served from the domain root, use root-relative paths (/images/logo.png). If the app is served from a subfolder (GitHub Pages project sites, itch.io), set the framework's base path (e.g. Vite base: "./") instead of hand-editing URLs.
- Never reference local file system paths (C:\..., /Users/...) or files outside the public folder.
- File names are case-sensitive on most hosts: match the exact case.
- After adding, renaming or removing a route, update every internal link, redirect and the sitemap. No links to routes that don't exist.
- Images always have width and height (or an aspect ratio) and meaningful alt text.
## 5. Fat client bundles
- Don't import a whole library for one function (lodash, moment, full icon packs). Import the specific module or use the platform (Intl, Array methods, fetch).
- Keep data fetching and heavy logic on the server when the framework supports it (server components, loaders, API routes).
- Lazy-load below-the-fold components, charts, editors and maps.
- Ask before adding a dependency, and say what it adds.
- Before finishing a feature, check the build output for any client chunk that grew a lot and explain why.
How to install
- Cursor: create
.cursor/rules/in your repo root and save the file asship-safe.mdc.alwaysApply: trueloads it in every chat. - Claude Code: paste the body into
CLAUDE.mdat the repo root, then run/memoryto check it loaded. - Codex, OpenCode and other agents: paste the body into
AGENTS.mdat the repo root. - Lovable or Bolt: paste the sections that apply into Project settings → Knowledge.
- Commit it, then ask your agent to review the current code against these rules once.
Want the general rules too? Grab the free Starter Cartridge, or the Rules Mega Pack ($19) with a longer launch-safety rule and stack rules for Next.js, FastAPI, Godot, Unity and discord.js.
Sister project: check a live app for these issues with a free scan at tryshipcheck.com