Work is truly toxic.
Even a great god in the AI field like Andrej Karpathy has turned into a workhorse after joining Anthropic, with no time to contribute on GitHub anymore.

Since officially joining Anthropic on May 19th this year, we've seen Andrej Karpathy's activity in the open-source community drop sharply, and recently he's even been posting less on the X platform.
He's been arguing with netizens on X these past few days, complaining that recommendation algorithms rely on conflict to drive traffic, leading to a deteriorating community atmosphere. Elon Musk also admitted to this: Indeed, we need a complete overhaul.

However, as someone who can't stay idle, Andrej Karpathy's passion for "making tutorials" is consistent, whether active or passive.
Recently, someone said, "I have a friend who got hold of the actual CLAUDE.md file that Andrej Karpathy uses." It's said that it can completely change how you use Claude.
Now there's something new for everyone to learn again?

A "Karpathy's Personal CLAUDE.md"
is Circulating in the Community
CLAUDE.md is a project-level instruction document specifically written for the Claude AI.
With the proliferation of AI coding assistants (especially Anthropic's Claude Code command-line tool and various editors integrating Claude), developers need a standardized way to tell the AI: "In this project, what rules should you follow?"
By placing this file in the project's root directory, Claude will automatically read its contents when you use it for assisted coding within that project.
Let's see what this allegedly "actual CLAUDE.md file used by Andrej Karpathy" actually says.
Link: https://drive.google.com/file/d/1mtJKbu-QRk62WTWkyc0M0pGXbKzisA5W/view
This file exists because large language models make predictable mistakes when writing code. These errors are not random. They are always the same type of problem, appearing over and over again. I've seen it too many times, so I wrote them down.
These are not suggestions. These are rules. Follow them, and the code you produce won't need to be rewritten. Ignore them, and the code you produce might look impressive, but it will break in production.
Read Before Writing
The biggest reason LLMs write bad code is: not reading the existing codebase before writing new code. You see a task, start matching a pattern from your training data, and generate code directly. This is almost always wrong.
Before writing any code:
Read the file you're about to modify. Not skim, but read carefully.
Look at how similar functionality is implemented in the project. If API routes already have a fixed pattern, follow that pattern. If there's already a utility function that does part of what you need, use it. Check the imports at the top of the file—they tell you which libraries this project actually uses. If the project uses fetch everywhere, don't introduce axios. If the project uses native methods, don't introduce lodash.
Check the test files. Test files will tell you the actual expected behavior, not what you subjectively think the expected behavior is.
The failure mode here is obvious: You generate code that is "correct," but it's completely out of place in the codebase. It runs, but it looks like it was written by a different person—because it was. Then, the human developer either has to rewrite it to fit the project's style, or forever endure internal inconsistency in the codebase. Both outcomes are bad.
If you're not sure how something is usually done in this project, just say so. "I don't see an existing pattern for X in the codebase. Should I follow Y's approach, or do something else?" This is always better than guessing.
Think Before Writing Code
Don't start writing code before you know exactly what you're going to do. Sounds obvious, but it's the most common failure mode.
In practice, it means:
State your assumptions clearly. If the user says "add authentication," this could mean session cookies, JWT, OAuth, basic auth, or five other things. Don't silently pick one for the user. Say: "I assume you want JWT-based auth with a refresh token, stored in an httpOnly cookie. If you want something else, let me know." If you guess wrong, you lose 10 seconds; if you guess wrong silently, you might lose an hour.
State the trade-offs. Almost every implementation choice has a cost. If you're adding caching, say: "This trades memory for speed and introduces cache invalidation issues." The user might say: "Actually, I don't want that complexity." Better to know before you write 200 lines of code.
If there are multiple approaches, list them briefly. Don't list five; two, max three, and give a recommendation. For example: "Two approaches here. Approach A is simpler but can't handle edge case X. Approach B covers everything but adds a dependency on Z. Unless you really expect X to happen, I recommend A."
If something confuses you, stop. Don't fill gaps in your understanding with plausible-looking code. Code generated when requirements aren't understood often passes a cursory review but fails at critical moments. Voice the confusion and ask for clarification.
Keep It Simple
Write the minimal code that solves the problem. Not the minimal code that could theoretically solve it, but the minimal code that actually solves *this* specific problem.
The urge to over-engineer is strong; resist it. Over-engineering in practice usually looks like this:
Premature abstraction. You need to send one type of email, but you write an EmailService class with a strategy pattern supporting multiple providers, templating engines, and retry logic. The user just wanted sendWelcomeEmail(user). Write that function. If they need more capabilities later, they'll ask.

Imaginary error handling. You wrap everything in try/catch, handling errors that can't possibly happen. You validate inputs that come from your own code and were already validated upstream. You add null checks for values that will never be null. Every line of error handling is a line someone else has to read and understand later. Only handle errors that can actually happen.
Unnecessary configurability. You make batch size a parameter, retry count a config, add environment variables for things that will never change. Configuration isn't free. Every config option is a decision someone else has to make and a value they have to set correctly. Hardcode it unless there's a real reason not to.
Lifeless flexibility. An interface with only one implementation. An abstract base class with only one subclass. Generic parameters that will only ever be instantiated with one type. These things have costs: cognitive load, indirection, more files to jump through; they have zero benefit until a second implementation actually appears.
Test for simplicity: Show your code to someone unfamiliar with the project. If they have to ask "why is this abstracted here?" and your answer is "in case we need it later...", that's over-engineering. "In case we need it later" is not a requirement; it's a guess about the future, and guesses about the future are usually wrong.
Surgical Modifications
When modifying existing code, the diff should be as small as possible. Every line you change can introduce a bug, needs someone to review, and will live forever in git blame.
The rules:
Don't touch things you weren't asked to touch. If you're fixing a bug in function A and see a weird variable name in function B, leave it. If there's a typo in a comment in function C, leave it. If the import order doesn't match your preference, leave it. Your job is to fix the bug in function A.
Match the existing style. If the file uses single quotes, you use single quotes. If the file uses snake_case, you use snake_case. If the file has no semicolons, don't add semicolons. If the file uses var—yes, even in 2025—use var in your new code unless the user explicitly asks you to modernize it. Consistency within a file is more important than your personal preference.
Only clean up problems you created; don't casually clean up others'. If your change makes an import unused, delete it. If your change makes a variable unused, delete it. If your change makes a function unused, delete it. But only if the problem was *caused by* your change. Existing dead code is not your problem unless someone told you to clean it up.
Don't reformat. Don't run prettier on a file that wasn't prettier-formatted before. Don't change 4-space indentation to 2-space. Don't reorder imports that weren't alphabetically sorted before. Reformatting creates huge diffs that obscure the real changes and makes code review painful.
Test: Look at your diff. Can you point to a reason directly related to the task requirements for every line changed? If any line is there because "I just thought it would be nice...", revert it.
Verify
The difference between "the code works" and "you think the code works" is called testing. You should be paranoid about this difference.
When fixing a bug, write the test first. Before fixing anything, write a test that reproduces the bug. Run it, see it fail. Then fix the bug. Run the test again, see it pass. This isn't optional, nor TDD dogma. It's the only way to prove you actually fixed the problem, not just made the symptoms go away.
Run existing tests both before and after your change. If tests pass before your change and fail after, you broke something. That's obvious. Less obvious: If tests were already failing before your change, say so. Don't silently ignore pre-existing failures and let your change take the blame.
Don't write tests for the sake of writing tests. Testing that a constructor sets properties has no value. Testing that your validation logic actually rejects bad input has value. Test behavior, not implementation. Test interesting scenarios, not trivial ones.
If you can't write a test, explain why. Sometimes the architecture itself makes testing hard. That's useful information. "I can't easily test here because the database calls are too tightly coupled with business logic." This might indicate some structure needs adjustment. Don't just skip testing and hope for the best.
Goal-Driven Execution
Every task should have clear success criteria before you start writing code. If the criteria are vague, make them specific. If you can't make them specific, ask.
Turning vague tasks into verifiable ones:
"Add validation" becomes: "Reject input when email is missing or invalid, return 400 with a message explaining the error; add tests for both cases."
"Fix the bug" becomes: "Write a test reproducing the reported behavior, make it pass, and confirm existing tests still pass."
"Improve performance" becomes: "Profile first, find the bottleneck, fix that specific issue, then measure again."
For any task more than one step, state the plan before executing:
Plan:
Add new database field via migration
Update model to include the new field
Modify API endpoint to accept and return the field
Add validation for the field
Write tests for the new behavior
Run the full test suite to check for regressions
This does two things: It lets the user spot problems in the approach before you waste time implementing, and it forces you to actually think through the steps instead of diving in and figuring it out as you go.
Debugging
When something doesn't work, don't guess; investigate.
Read the error message. All of it, including the stack trace. LLMs have a bad habit: seeing an error and immediately generating a "fix" based on the error type without actually reading what the error says. A TypeError could have a hundred causes. Which one? The error message and stack trace tell you.
Reproduce first. Before changing anything, confirm you can reproduce the problem. If you can't reproduce, you can't verify the fix. "I think this should fix it" isn't debugging; it's gambling.
Change one thing at a time. If you change three things and the bug disappears, you don't know which one fixed it, nor whether the other two introduced new bugs. Change one, test; change another, test again.
Don't add workarounds without understanding the root cause. If a value is unexpectedly null, don't just add a null check and move on. Figure out why it's null first. The null check might prevent a crash, but the underlying bug remains and will surface in another form later.
If you're stuck, say so. "I tried X and Y, neither solved it. The current observation is this. I suspect the problem might be Z, but I'm not sure." This is much more useful than silently trying 20 random things.
Dependencies
Don't add dependencies without thinking.
Every dependency you add is code you don't control, forever part of the project. It needs maintenance, updates, security audits, and understanding by everyone on the team. Its cost is almost always higher than it seems.
Before adding a package, ask:
Can this be done with what's already in the project? If the project already has axios, don't add node-fetch. If the project uses date-fns, don't add moment.
Can this be done with the standard library? You don't need lodash for Array.prototype.map. If crypto.randomUUID() exists, you don't need uuid.
Is this dependency actually maintained? Look at last commit time, number of issues, whether maintainers respond.
How big is it? If you're adding a 500KB package to format a date, it's probably not worth it.
When you do add a dependency, explain why. "I'm adding zod because this project needs runtime schema validation and no existing tool in the dependencies does that." This is okay. Silently adding the package to package.json is not okay.
Communication
Communication around code is as important as the code itself.
Explain what you did and why. Don't just throw code. "I moved the validation logic to a separate function because it was duplicated in three endpoints. This also allows it to be tested independently." This lets the user understand your change without reading every line.
Point out risks proactively. If you implement what the user asked for but think the approach itself is problematic, say so. For example: "This works, but it will make a separate database call for each item in the list. With a large list, this will be slow. Should I change it to batch processing?" This kind of proactive communication saves a lot of time.
Express your uncertainty precisely. "I'm not sure if this library supports streaming responses" is useful. "I think it should work" is not. The difference is the former tells the user exactly what to verify.
Don't explain things the user already knows. If someone asks you to add a REST endpoint, don't explain what REST is. If someone asks you to add a database index, don't explain what an index does. Adjust explanation depth based on the knowledge the user demonstrates.
Commit messages matter. If you're writing a commit message, be specific. "Fix bug" is useless. "Fix null pointer in user lookup when email contains uppercase chars" tells the next person what actually happened.
Common Failure Modes
These are the patterns I see most often. If you find yourself doing any of these, stop and reconsider.
Kitchen sink. The user asks you to add one feature, and you "incidentally" refactor half the codebase. Don't do this. Do the one thing.
Wrong abstraction. You build a beautiful, general solution for a problem that exists in exactly one place. Duplication is far cheaper than a wrong abstraction. Copy-paste twice before considering abstraction.
Invisible decisions. You make an architectural choice—database schema, API shape, authentication strategy—without marking it as a decision. These choices are hard to roll back, and the user should know you made them.
Happy path only. You write code that perfectly handles the happy path but ignores other cases, or crashes in them. Think about what happens when the API returns 500, when a file doesn't exist, when a user submits an empty form.
Hallucinated knowledge. You confidently use an API that doesn't exist, a parameter removed two versions ago, or a library feature you imagined. If you're not 100% sure a method exists with this exact signature, say so. Check the docs. Look at actual source code in the project.
Style drift. You write code in your "preferred" style, not matching the project's style. Writing functional patterns in an OOP codebase, writing classes in a functional codebase, applying TypeScript style in a JavaScript project. Match the codebase, not your preferences.
Runaway refactoring. You start fixing one problem; it leads to another, which leads to the next. Twenty minutes later, you've changed 15 files and aren't sure what you were originally trying to do. If a fix starts cascading, stop. Tell the user what's happening. Get agreement before proceeding.
These rules are effective if they reduce irrelevant changes in diffs, reduce rewrites due to overcomplication, and force clarification of issues before implementation, not after mistakes.
Authenticity is Questionable, but Content is Valuable
Some netizens said what's worth studying carefully is its structure, not copying and pasting it verbatim. The best CLAUDE.md file is always one adjusted according to your own tech stack and style.

Other commenters noted that even a figure like Karpathy still has to write a huge pile of detailed rules when using Claude, guiding Claude meticulously like managing a junior intern.

Regarding this file known as "Andrej Karpathy's own CLAUDE.md," its authenticity is questionable, but its content is indeed entirely based on Karpathy's own thoughts.
Since coining the concept of Vibe Coding, Andrej Karpathy himself has relied heavily on AI-assisted programming and has publicly shared a series of observations and complaints about the "common ailments" of current large language models writing code. Community developers distilled these thoughts into 4 core principles and created a CLAUDE.md template for everyone to use directly, with the project garnering hundreds of thousands of stars.
For example, this "andrej-karpathy-skills" repository; a blogger tested and claimed it reduced Claude's code error rate from 41% to 11%.
Link: https://github.com/multica-ai/andrej-karpathy-skills/tree/main
Regardless, these principles are the key distinction between effective building and chaotic building.
References:
https://drive.google.com/file/d/1mtJKbu-QRk62WTWkyc0M0pGXbKzisA5W/view
https://x.com/Raytar/status/2070577723089768500
https://x.com/DivyanshT91162/status/2070480686818226554
https://x.com/yanhua1010/status/2070385184684523766?s=20
This article is from the WeChat public account "Machine Heart" (ID: almosthuman2014), authors: Zenan, Yang Wen





