I've been using Claude Code as my primary development tool since early 2025. After hundreds of sessions on Rust, TypeScript and React projects, I've built a configuration that evolves every week. This article shows the setup as it is today, with real files.
The structure: where config lives
Everything starts from ~/.claude/. That's Claude Code's global directory. Here's how mine is organized:
~/.claude/
CLAUDE.md # global instructions
settings.json # model, hooks, permissions, skill overrides
RTK.md # MCP RTK reference (loaded via @RTK.md)
agents/
netir-reviewer/ # custom Rust review agent
skills/ # symlinks to the config repo
blog -> .../global/skills/blog/
commit-push -> .../global/skills/commit-push/
netir-cpm -> .../projects/netir/skills/netir-cpm/
...
The trick: skills are symlinks to a Git configuration repo that I maintain separately. This lets me version, sync across machines, and separate global skills from project-specific ones.
CLAUDE.md: the most important file
The global CLAUDE.md is loaded into every session. This is where I put rules that apply everywhere, regardless of the project.
Mine is under 30 lines. Each line was added after a real problem:
## French language -- Strict orthography
- Always respond in French with all correct diacritical marks.
- FORBIDDEN to write without accents.
- Never launch subagents or delegate tasks unless the user explicitly asks.
- Output code first, explanation after - only if non-obvious.
- No compliments or affirmations in code reviews. State the issue, show the fix, stop.
- No em dashes, smart quotes, or decorative Unicode.
## Git & GitLab
- Simple feature branch workflow: feature branches merge into main.
- Always use conventional commit messages.
@RTK.md
A few key points:
- The language rule comes first because without it, Claude switches to English or drops accents after context compaction.
- "Never launch subagents unless asked" prevents Claude from delegating to sub-agents when it's unnecessary. Without this rule, it spawns agents for simple searches and wastes context.
-
@RTK.mdis a reference to a separate file documenting RTK commands. Claude loads it automatically when it needs the context.
Rules: contextual instructions
Rules are Markdown files in ~/.claude/rules/ (or in the config repo). The difference from CLAUDE.md: they have a paths header that activates them only on matching files.
I have 15. Here are the most useful ones:
Code discipline
---
paths: "**/*.{rs,ts,tsx,jsx,js,sql,toml}"
---
# Code discipline
## Prior art - search before writing
Before writing a helper or abstraction: grep 2-3 variants
of the concept. If an equivalent exists, reuse it.
This rule activates on all code files. It prevents Claude from recreating utilities that already exist in the project.
Security
---
paths: "**/*.{rs,ts,tsx,sql,toml,yml,yaml},**/Dockerfile"
---
- Secrets: never hardcoded. Use env vars or vault.
- Injections - zero tolerance: Always use parameterized queries.
- JWT stateless by default. Short-lived access + long-lived refresh.
- HTTP security headers: CORS, X-Content-Type-Options, HSTS, CSP.
Anti "fake done"
# Agent Verification -- 11 "Fake Done" Shortcuts
Before marking any task as complete, verify the diff against each shortcut.
If any applies, the task is NOT done.
1. Relaxed tests - assertions weakened to make red go green
2. Swallowed errors - try/catch that hides the failure
3. Stub returns - hardcoded return values
4. Comment-as-fix - the bug is now a TODO
5. Happy-path only - 500s, empty inputs unhandled
...
This one is agent-specific. When Claude marks a task as done, it must check its own diff against these 11 patterns. It catches cases where the code compiles but doesn't solve the actual problem.
Other rules cover: Rust imports, layered architecture, database migrations, JavaScript/TypeScript pitfalls, performance, refactoring, SQLx compile-time checks, and testing.
Skills: custom slash commands
Skills are SKILL.md files in folders under ~/.claude/skills/. Each skill defines a slash command (e.g., /commit-push) with detailed instructions.
I have 55 skills installed with 40 active (15 disabled via skillOverrides in settings.json). They fall into three categories:
Daily workflow skills
-
/commit-push- auto-generated conventional commit message + push in one command -
/cpm- commit, push and GitLab Merge Request creation in one command -
/dev-pipeline- plan, implement, lint, test, review, ship - the full pipeline -
/lint-check-cargo fmt && cargo clippy && cargo checkwith auto-fix -
/work-on-issue- fetch a GitLab issue, assign, plan, implement, test, verify
Review and quality skills
-
/security-audit- OWASP top 10 audit on the codebase -
/systematic-debugging- structured debugging methodology -
/netir-qa-swarm- 4 reviewers in parallel on a MR (architecture, security, Rust quality, business patterns) -
/netir-review-triage- sorts review comments into actionable/nit/ambiguous
Content skills
-
/blog- complete article creation pipeline (research, writing, SEO, scoring) -
/linkedin-post-coach- interactive coaching for LinkedIn posts -
/useful-for-me- analyzes an external repo/tool and tells me if it's useful for my projects
Project-specific skills
The Netir setup illustrates project-specific skills well. These skills live in projects/netir/skills/ and only activate inside the Netir directory:
netir-cpm # CPM with Netir conventions (labels, reviewer)
netir-qa-swarm # multi-agent review
netir-review-triage # review sorting
netir-alert-triage # monitoring alert triage
netir-tech-debt # tech debt analysis
netir-next # next task selection
A skill is just a Markdown file with instructions. Here's a simplified excerpt of /commit-push:
# Commit & Push
1. git status to see modified files
2. git diff to analyze changes
3. git log -5 for existing commit style
4. Generate a conventional message (feat/fix/refactor...)
5. git add relevant files
6. git commit
7. git push
The power comes from composition: /dev-pipeline internally calls /lint-check, then chains with review and commit.
Disabling unused skills
The 15 disabled skills are set in settings.json:
{
"skillOverrides": {
"cost-estimate": "off",
"email-campaigns": "off",
"tdd": "off",
"teach": "off"
}
}
This avoids cluttering autocompletion and prevents Claude from invoking them accidentally.
Hooks: automate without thinking
Hooks are shell commands executed automatically on certain events. The most important one in my setup:
The RTK integration
RTK (Rust Token Killer) is an open source tool that integrates with Claude Code via a PreToolUse hook. It intercepts Bash commands and filters outputs to reduce token consumption.
The configuration is a single entry in settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "rtk hook claude"
}
]
}
]
}
}
RTK runs before every Bash command. It intercepts CLI commands (git status, find, grep, ps aux...) and rewrites them to go through its filtering proxy. Result: CLI outputs are filtered automatically, without Claude or me having to think about it.
The numbers on my current setup:
Total commands: 39,646
Tokens saved: 276.4M (86.8%)
Top commands:
rtk read 3,067 calls 217.8M tokens saved
rtk grep 5,408 calls 13.8M tokens saved
rtk find 573 calls 11.8M tokens saved
On Opus ($15/M tokens for input), 276 million tokens saved represents roughly $4,100 in savings. The hook pays for itself in the first session.
I also built MCP RTK, a complementary proxy that applies the same filtering principle to MCP server responses (GitLab, Grafana, Sentry...).
Custom agents
Agents are files in ~/.claude/agents/. They define a specialized profile with restricted tools.
I have a single custom agent: netir-reviewer, a Rust code reviewer specific to the Netir project. It checks layered architecture, SQLx conventions, error handling, imports, OpenAPI registration, and tracing.
The difference between a skill and an agent: a skill gives instructions to the main session, an agent is a separate session with its own context and tools. A review agent only has access to Read and Grep, not Edit or Write - it can't modify code, only read it and flag issues.
The configuration repo
This entire setup is managed in a private Git repo:
~/Documents/dev/claude/personal-config/
install.sh # setup script (symlinks, copies)
global/
CLAUDE.md # global instructions
rules/ # 15 rule files
skills/ # global skills (blog, commit-push, etc.)
projects/
_template/ # template for new projects
netir/ # Netir-specific config
agents/
rules/
skills/
jarvis/ # Jarvis-specific config
install.sh creates symlinks from ~/.claude/skills/ to the repo. When I add a skill or modify a rule, a git pull on another machine is enough to sync.
The project template
The _template/ folder contains a base structure for starting a new project with Claude Code:
cp -r projects/_template projects/my-new-project
# Adapt rules and skills to the project
./install.sh
What I've learned
After months of iterating on this config:
Keep CLAUDE.md short. Early versions were 200+ lines. Claude would skim them and forget rules. Under 30 well-chosen lines are more effective than an exhaustive document.
Contextual rules beat a big CLAUDE.md. Loading Rust rules only on .rs files saves context and avoids confusion between languages.
Disable unused skills. 55 skills is too many. The 15 disabled ones don't serve my current workflows. Keeping them active slows autocompletion and adds noise.
A single well-placed hook is enough. The RTK hook on PreToolUse covers 90% of optimization needs. No need for complex hooks on every event.
Version your config. A Git repo for Claude Code config seems overkill at first. In practice, it lets you roll back when a change breaks something, and sync between machines without friction.
The setup keeps evolving. Every repeated friction in a Claude Code session becomes a candidate for a new rule, a new skill, or a hook adjustment. To go further: my guide on writing effective skills details the patterns and anti-patterns, and the projects page lists the other tools I've built around this ecosystem.
Top comments (1)
The layering with a global CLAUDE.md plus per-project rule files is where I converged too, after the same failure mode: rules that live only inside one project's context rot silently the week the stack changes, and nobody notices until the agent keeps suggesting the old pattern.
One question on hooks: how do you keep them fast enough not to tax every session? Mine quietly turned into mini CI jobs before I cut them down to only checks that finish under a second. Anything you tried and removed since?