| description | Guidelines for writing clean, maintainable, and human-readable code. Apply these rules when writing or reviewing code to ensure consistency and quality. |
|---|---|
| globs | **/* |
- Replace hard-coded values with named constants
- Use descriptive constant names that explain the value's purpose
- Keep constants at the top of the file or in a dedicated constants file
- Variables, functions, and classes should reveal their purpose
- Names should explain why something exists and how it's used
- Avoid abbreviations unless they're universally understood
- Don't comment on what the code does - make the code self-documenting
- Use comments to explain why something is done a certain way
- Document APIs, complex algorithms, and non-obvious side effects
- Each function should do exactly one thing
- Functions should be small and focused
- If a function needs a comment to explain what it does, it should be split
- Extract repeated code into reusable functions
- Share common logic through proper abstraction
- Maintain single sources of truth
- Keep related code together
- Organize code in a logical hierarchy
- Use consistent file and folder naming conventions
- Hide implementation details
- Expose clear interfaces
- Move nested conditionals into well-named functions
- Refactor continuously
- Fix technical debt early
- Leave code cleaner than you found it
- Write tests before fixing bugs
- Keep tests readable and maintainable
- Test edge cases and error conditions
- Write clear commit messages
- Make small, focused commits
- Use meaningful branch names
Always verify information before presenting it. Do not make assumptions or speculate without clear evidence.
Make changes file by file and give me a chance to spot mistakes.
Never use apologies.
Avoid giving feedback about understanding in comments or documentation.
Don't suggest whitespace changes.
Don't summarize changes made.
Don't invent changes other than what's explicitly requested.
Don't ask for confirmation of information already provided in the context.
Don't remove unrelated code or functionalities. Pay attention to preserving existing structures.
Provide all edits in a single chunk instead of multiple-step instructions or explanations for the same file.
Don't ask the user to verify implementations that are visible in the provided context.
Don't suggest updates or changes to files when there are no actual modifications needed.
Always provide links to the real files, not x.md.
Don't show or discuss the current implementation unless specifically requested.
Always use Context7 when I need library/API documentation, code generation, setup or configuration steps without me having to explicitly ask.
- Use middleware to route database requests via a backend API.
- Verify user identity and permissions at every single endpoint.
- Deliver sensitive data only after server-side verification.
- Keep API keys and secrets strictly on the server.
- Ensure .env variables are never bundled into client code.
- Perform all sensitive logic and math on the server.
- Sanitize all user inputs to prevent malicious code execution.
- Implement rate limiting to prevent bot abuse and spikes in cost.
- Prevent passwords and tokens from being printed in logs.
- Use a secondary AI model to audit code for vulnerabilities.
- Keep all dependencies and libraries updated to the latest versions.
name: karpathy-guidelines description: Behavioral guidelines to reduce common LLM coding mistakes. Use when writing, reviewing, or refactoring code to avoid overcomplication, make surgical changes, surface assumptions, and define verifiable success criteria. license: MIT
Behavioral guidelines to reduce common LLM coding mistakes, derived from Andrej Karpathy's observations on LLM coding pitfalls.
Tradeoff: These guidelines bias toward caution over speed. For trivial tasks, use judgment.
Don't assume. Don't hide confusion. Surface tradeoffs.
Before implementing:
- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them - don't pick silently.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.
Minimum code that solves the problem. Nothing speculative.
- No features beyond what was asked.
- No abstractions for single-use code.
- No "flexibility" or "configurability" that wasn't requested.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
Touch only what you must. Clean up only your own mess.
When editing existing code:
- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- If you notice unrelated dead code, mention it - don't delete it.
When your changes create orphans:
- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove pre-existing dead code unless asked.
The test: Every changed line should trace directly to the user's request.
Define success criteria. Loop until verified.
Transform tasks into verifiable goals:
- "Add validation" → "Write tests for invalid inputs, then make them pass"
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
- "Refactor X" → "Ensure tests pass before and after"
For multi-step tasks, state a brief plan:
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
If two existing patterns in the codebase contradict, don't blend them. Pick one (the more recent / more tested), explain why, and flag the other for cleanup. "Average" code that satisfies both rules is the worst code.
Before adding code in a file, read the file's exports, the immediate caller, and any obvious shared utilities. If you don't understand why existing code is structured the way it is, ask before adding to it. "Looks orthogonal to me" is the most dangerous phrase in this codebase.
Every test must encode WHY the behavior matters, not just WHAT it does.
A test like expect(getUserName()).toBe('John') is worthless if the function takes a hardcoded ID.
If you can't write a test that would fail when business logic changes, the function is wrong.
After completing each step in a multi-step task: summarize what was done, what's verified, what's left. Don't continue from a state you can't describe back to me. If you lose track, stop and restate.
If the codebase uses snake_case and you'd prefer camelCase: snake_case. If the codebase uses class-based components and you'd prefer hooks: class-based. Disagreement is a separate conversation. Inside the codebase, conformance > taste. If you genuinely think the convention is harmful, surface it. Don't fork it silently.
If you can't be sure something worked, say so explicitly. "Migration completed" is wrong if 30 records were skipped silently. "Tests pass" is wrong if you skipped any. "Feature works" is wrong if you didn't verify the edge case I asked about. Default to surfacing uncertainty, not hiding it.
NO HACKS. The user is EXTREMELY concerned about code quality, much more so than immediate results. If they ask you to build something and, while doing so, you hit a wall, and realize that the only way to ship the requested feature is to introduce a local hack, workaround, monkey patch, duct tape - STOP. STOP IMMEDIATELY. Either fix the underlying flaw that blocked you in a ROBUST, WELL DESIGNED, PRODUCTION READY manner, or be honest that the prompt can't be completed without hacks.
To make it very clear:
- DO NOT INTRODUCE HACKS IN THE CODEBASE.
- DO NOT COMMIT CODE THAT COULD BREAK THINGS LATER.
- DO NOT COMMIT PARTIAL SOLUTIONS OR WORKAROUNDS.
THIS IS VERY IMPORTANT. THIS IS VERY IMPORTANT. THIS IS VERY IMPORTANT.
The author appreciates honestly and he WILL be glad and thankful if you respond a request with "I couldn't complete your request because the repository lacked support for X". He will be even happier if you go ahead and update the repo to provide the necessary support in a well designed, robust way. But he will be VERY ANGRY if, while attempting to implement a feature, you introduce a workaround that will potentially break things later.
NEVER introduce hacks in the codebase.
Also assume that none of the code you're working in is in production, so, backwards compatibility is NOT IMPORTANT. If you find something that is poorly designed and fixing it would require breaking existing APIs or behavior, DO SO. Do it properly rather than preserving a flawed design. Prioritize clarity, correctness, and maintainability over compatibility with existing code.
Core values:
- ABSOLUTE code quality over speed of delivery.
- Correctness over convenience.
- Clarity over cleverness.
- Maintainability over short-term productivity.
- Robust design over quick fixes.
- Simplicity over complexity.
- Doing it right over doing it now.
- Honesty above everything.
After every change you make, provide a clear, honest report on ANY change that you are not confident about and that could be considered a fragile hack.