Claude Code got much better for me when I stopped re-explaining myself in every chat. I have been coding with AI for about two years, using Claude Code for roughly the last six months, and the most useful improvement was embarrassingly simple: put my default rules into ~/.claude/CLAUDE.md and let the agent start there.

Before that, I kept burning messages on the same stuff. Use strict typing. Do not add fallbacks I did not ask for. Keep the diff small. Do not rewrite half the file because you got excited. Claude usually listened. I still had to pay that tax again and again.

Now the baseline is already there before the repo even enters the conversation.

Where I Keep My Claude Code Global Instructions

Anthropic's Claude Code docs split this into a few layers. ~/.claude/CLAUDE.md is the user-wide file. ./CLAUDE.md or ./.claude/CLAUDE.md is the shared project layer. CLAUDE.local.md is for your own project notes that should stay out of git.

That is almost exactly how I want it:

  1. ~/.claude/CLAUDE.md for my persistent coding preferences
  2. Project CLAUDE.md for repository-specific architecture and commands
  3. CLAUDE.local.md when I need personal project notes that should stay out of git

I do not want to paste the same personal rules into every repository I open. If "no silent fallbacks" is a global preference, it belongs in the global file. If "run this weird internal bootstrap command before tests" is repo-specific, it belongs in the project file.

Here is the version I am using right now in Claude Code:

Claude Code global instructions in CLAUDE.md for persistent AI coding rules

The Claude Code Rules I Actually Use

This block is boring on purpose. Good rules usually are. I am not trying to describe every edge case in advance. I just want Claude Code to stop making the same predictable mistakes.

# Global Rules

## Code Style

- Comments in English only
- Prefer functional programming over OOP
- Use OOP classes only for connectors and interfaces to external systems
- Write pure functions - only modify return values, never input parameters or global state
- Follow DRY, KISS, and YAGNI principles
- Prefer simple, native, vendor-recommended solutions and avoid premature abstractions
- Use strict typing for returns, variables, collections, and complex data; validate external/API data at runtime; require needed fields, ignore unrelated extra fields, prefer structured models over loose dictionaries, and avoid weak generic types like `Any`, `unknown`, or `List[Dict[str, Any]]`
- Check if logic already exists before writing new code
- Never use default parameter values - make all parameters explicit
- Write simple single-purpose functions - no multi-mode behavior, no flag parameters that switch logic. If the user needs multiple modes, they will ask explicitly

## Error Handling

- Always raise errors explicitly, never silently ignore them
- Use specific error types that clearly indicate what went wrong
- Avoid catch-all exception handlers that hide the root cause
- No fallbacks, symptom-masking guards, or silent recovery unless I explicitly ask for them; fix root causes and make code either succeed or fail with a clear error
- External API or service calls: use retries with warnings, then raise the last error
- Error messages must be clear, actionable, and specific: explain what failed and why, include request params, response body, status codes, and avoid generic "something went wrong"
- Logging should use structured fields instead of interpolating dynamic values into message strings

## Libraries and Dependencies

- Use modern stable, project-compatible package management, libraries, and language standards; prefer vendor-recommended patterns such as ESM when supported
- Install dependencies in project environments, not globally
- Add or update dependencies in project config files, not as one-off manual installs
- If a dependency is installed locally, read its source code when needed instead of guessing, even if it is gitignored

## Testing

- Respect the repository test strategy and add only the minimum useful tests for the requested change
- Prefer smoke, integration, and end-to-end tests over narrow unit or regression tests; do not test static text, prompts, or config unless behavior depends on them
- Do not create fake/mock-based tests by default; use real integrations when practical, even if they cost a little money
- UI tests and automations must use stable IDs, test IDs, or accessibility IDs instead of visible text, and fail fast without fallback clicks

## Terminal Usage

- Prefer non-interactive commands with flags over interactive ones
- Always use non-interactive git diff: `git --no-pager diff` or `git diff | cat`

## Workflow

- Read the existing code and relevant project instructions before editing
- Keep changes minimal and tightly scoped to the current request: make the smallest useful diff, change only the lines needed to solve the problem, and avoid unrelated improvements unless the user asks for them
- Match the existing style of the repository even if it differs from my personal preference; new code must look like it was written by the same author
- Keep files small and cohesive; split by feature or responsibility when the project has no established structure
- Do not revert unrelated changes
- If you are unsure, inspect the codebase instead of inventing patterns
- When project instructions include test or lint commands, run them before finishing if the task changed code

## Documentation

- Code is the primary documentation - use clear naming, types, and docstrings
- Keep documentation in docstrings of the functions, classes, or modules they describe, not in separate files
- Separate docs files only when a concept cannot be expressed clearly in code, and only one file per topic
- Never duplicate documentation across files; reference other sources instead
- Store knowledge as current state, not as a changelog of modifications

## Commits

- Never create a git commit unless the user explicitly asks for one
- Prefer `git merge` over `git squash` whenever possible, unless the user explicitly asks for squash.
- Uncommitted changes are the user's review state - they read the diff before deciding what to commit
- Keep changes uncommitted until asked, so the diff stays clean and reviewable

That block covers most of what I care about day to day.

Without it, Claude drifts in very familiar ways. It adds fallback behavior "just in case." It widens types because strict typing feels inconvenient. It wraps simple functions in extra layers. It fixes the wrong problem because it is trying to be accommodating instead of exact.

I would rather spend ten minutes writing a decent global file once than keep correcting those patterns one by one in every new session.

Global CLAUDE.md First, Project CLAUDE.md Second

I do not want one giant CLAUDE.md with everything jammed into it.

My global file should answer questions like:

  • How strict should typing be?
  • How do I want errors handled?
  • Do I want minimal diffs or broad refactors?
  • What kind of documentation do I expect?

My project file should answer different questions:

  • How do I run the project?
  • Which commands are safe and expected?
  • What are the important architecture boundaries?
  • Where do tests live?
  • Which conventions are specific to this repo only?

In practice:

  • global CLAUDE.md says how I work
  • project CLAUDE.md says how this repo works

When those two things get mixed together, the file turns into sludge. Half of it is too generic, half of it is too local, and Claude has to carry all of it around on every task.

Anthropic recommends keeping these files concise. Good. Long instruction files usually read like somebody tried to shove a whole engineering handbook into the prompt. That never ends well.

What Breaks Mid-Session

Rules help. They do not rescue a messy session forever.

If I spend twenty messages discussing one subsystem and then suddenly switch to a different problem, Claude can stay mentally stuck in the earlier frame. That is normal. I do not treat long chats as sacred.

So in practice I do this:

  • Start a fresh session when the task changes from exploration to implementation
  • Start a fresh session when switching from one subsystem to a very different one
  • Keep project instructions concise enough that I am not paying context tax on every turn

That is also why I like markdown files for plans and notes. If the task is large, I would rather save the state explicitly than trust one long thread to stay clean.

My Practical Rollout for Claude Code Rules

If I were setting this up from scratch today, I would do it in this order.

1. Create ~/.claude/CLAUDE.md

Start with your non-negotiables. Not life advice. Not engineering manifestos. Just the rules that repeatedly matter across repositories.

For me, that means:

  • strict typing
  • explicit error handling
  • minimal edits
  • no silent fallbacks
  • docstrings where documentation belongs
  • non-interactive terminal habits

That alone already changes the output more than most prompt tweaks.

2. Add a Project CLAUDE.md

Use the repo file for commands, architecture, naming, and boundaries. Anthropic gives you /init to draft one, which is useful. I still edit it manually after that because generated instructions are a draft, not a finished artifact.

3. Keep Project Rules Short

Do not turn the project file into a second copy of your personal one. Put repo-specific commands, architecture notes, and local conventions there. Leave your durable preferences in the global file.

Why This Matters More Than Clever Prompting

Most "ultimate setup" content about coding agents drifts into theater pretty quickly.

What actually improved my day-to-day work was much simpler:

  • a stable user-wide CLAUDE.md
  • a clean project CLAUDE.md

That stack makes Claude calmer. Fewer random fallbacks. Fewer cute abstractions. Fewer sessions where I realize ten minutes later that the agent and I were solving slightly different problems.

If you use several coding agents, the same pattern shows up elsewhere too. Different product, same lesson: set the baseline once and stop renegotiating it every morning.

If you want the companion articles, they live here:

About Author

Kirill Markin

Kirill Markin

Staff Software Engineer

Founder

10,000+
subscribers

Share this article