A walkthrough of my Claude Code configuration — rules, plugins, hooks, status line, memory system, and the workflows that make it all click.

I use Claude Code every day — hundreds of messages across Rust, Python, TypeScript, and C# projects. After months of tweaking, the configuration has become something I rely on more than any IDE extension. This post is a tour of what I've landed on and why.
Everything lives in ~/.claude/:
~/.claude/
├── CLAUDE.md # Global instructions (loaded every session)
├── settings.json # Permissions, hooks, plugins, status line
├── rules/ # 10 rule files (coding style, git, security, etc.)
├── projects/ # Per-project persistent memory
│ └── <project>/memory/
│ ├── MEMORY.md # Index of all memories
│ ├── user-profile.md
│ └── ...
├── skills/ # Custom skills (deep research, etc.)
│ ├── SKILL.md
│ └── templates/
├── statusline-command.sh # Custom status bar script
├── update-pricing.sh # Auto-fetch Anthropic pricing
└── cache/
└── model-pricing.env # Cached pricing data
This file gets loaded into every conversation. Mine tells Claude:
rules/I keep CLAUDE.md as an index pointing to detailed rules, not a wall of text. Easier to maintain and less likely to get ignored.
10 rule files in ~/.claude/rules/:
| File | What It Covers |
|---|---|
coding-style.md | One concept per file, functions under 50 lines, "why" comments |
git-workflow.md | Imperative commits, feature branches, linter-before-commit |
security.md | No secrets in code, parameterized SQL, HTTPS only |
testing.md | Happy path + edge cases + error paths, per-language frameworks |
rust.md | anyhow/thiserror, no unwrap(), Service<R: Repository> pattern |
python-django.md | Django 5 + DRF, mssql-django, managed = False models, uv not pip |
api-design.md | RFC 9457 errors, cursor pagination, rate-limit headers on all paths |
patterns.md | Repository pattern, error handling strategy per layer |
performance.md | Model selection (Sonnet 80%, Opus for deep work, Haiku for subagents) |
agents.md | When to delegate to subagents, parallel execution, plugin-to-task mapping |
These are global — they apply across all projects. Each project can also have its own CLAUDE.md with local overrides.
The payoff: Claude runs cargo clippy before Rust commits, uses uv instead of pip for Python, formats API errors as RFC 9457 — without me saying a word. Once you write the rule, you stop repeating yourself.
I run 12 plugins. Some are official Anthropic plugins, some are community-built.
Official plugins (from claude-code/plugins and claude-plugins-official):
/commit, /commit-push-pr)/simplify)Third-party plugins:
Third-party plugins are installed via extraKnownMarketplaces in settings.json:
{
"extraKnownMarketplaces": {
"interface-design": {
"source": {
"source": "github",
"repo": "Dammyjay93/interface-design"
}
}
}
}I also keep a plugin-to-task mapping in my agents.md rules so Claude reaches for the right tool:
| Task | Plugin |
|---|---|
| Plan a feature | /feature-dev or Plan mode |
| Review code / PR | /code-review |
| Simplify code | /simplify |
| Build frontend UI | /frontend-design |
| Git commit | /commit |
| Commit + push + PR | /commit-push-pr |
| Rust diagnostics | rust-analyzer-lsp |
| Browse/test web UI | playwright |
Hooks run shell commands before or after Claude uses a tool.
PreToolUse — a nudge before any Bash call:
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "echo '⚠️ Confirm branch and remote before pushing'"
}]
}The matcher field filters by tool name. You can add an if field for argument-level filtering (e.g. only matching git push). I keep mine broad.
PostToolUse — after any file edit, a linter reminder based on file extension:
FILE=$(echo "$CLAUDE_TOOL_INPUT" | jq -r '.file_path // empty')
if [[ "$FILE" == *.rs ]]; then
echo "Reminder: run cargo clippy"
elif [[ "$FILE" == *.cs ]]; then
echo "Reminder: run dotnet build"
elif [[ "$FILE" == *.py ]]; then
Not blocking, just a tap on the shoulder. Catches more than you'd think.
settings.json has allow/deny lists:
Allowed (auto-approved):
Read, Edit, Write, Glob, GrepBash (with deny-list exceptions)WebFetch, WebSearchDenied (hard-blocked):
rm -rf /, git push --force, git reset --hard, git clean -fdd, mkfs, shutdown, reboot, chmod 777npm publish, cargo publish, curl | bashcat ~/.ssh/*, cat *id_rsa*Even if Claude hallucinates a dangerous command, it can't execute it. Set this up before you need it.
My favorite customization. The terminal status line shows everything at a glance:
[Opus 4.6] misoto22-site | main | 45k 12k | 32% (57k/200k) | $0.45 | 12m30s | 3f +42 -8
From left to right:
The cost is calculated from cached pricing that refreshes daily. A small script scrapes Anthropic's pricing page, extracts per-model rates, and caches them locally:
if [ ! -f "$PRICING_CACHE" ] || \
[ "$(( $(date +%s) - $(stat -f %m "$PRICING_CACHE") ))" -gt 86400 ]; then
bash "$PRICING_SCRIPT" &>/dev/null & # auto-refresh when cache >24h old
fiNo API key needed. The color-coded context bar is what I actually watch most — it tells me when to /compact.
Memories survive across conversations. They're stored per-project at ~/.claude/projects/<project>/memory/ as markdown files with frontmatter:
---
name: user-profile
description: User identity, tech stack, and work preferences
type: user
---
Full-stack developer at Inovit (automotive wheels/tires/parts industry)...I group them into four types:
The MEMORY.md index keeps things scannable:
User
- user-profile.md — User identity, tech stack, and work preferences
Feedback
- feedback-patterns.md — Behavior corrections: pnpm not npm, verify API compliance
Project
- project-decisions.md — Cross-project architecture decisions
Reference
- toolchain.md — Local development environment version infoIn practice, this means Claude already knows I'm a native Chinese speaker who prefers terse responses, that my Efision project uses 5-layer Clean Architecture with Service<R> generics, and that npm instead of pnpm is a mistake I've corrected before. These details compound — they change how Claude approaches every task.
Skills are SKILL.md files in ~/.claude/skills/. Unlike plugins (which bundle tools, agents, and hooks), skills are pure markdown — step-by-step instructions Claude follows when you type /<skill-name>.
The one I use most is /ship. One command, working tree to merged PR:
gh pr checks every 30s (10min timeout); if CI fails, read logs, fix, push, retry up to twiceThe whole thing is defined in one markdown file. No code. Claude just follows the steps and stops to ask if something breaks. Replaces what used to be 5-10 manual commands.
I also have a Deep Research skill — 8 steps for turning a vague question into a structured report:
Triggers on "deep research", "对比分析", etc. Intermediate work goes to ~/Downloads/research/<topic>/ so nothing gets lost. Includes report templates for consistency.
I've also symlinked several design skills from the interface-design plugin — /arrange, /audit, /critique, /distill, /normalize — so they're globally available across projects.
Each project gets its own CLAUDE.md. My personal website's, for example:
pnpm (not npm)content/blog/@/i18n/navigation (not next/link)Global rules handle the universal stuff. Project rules handle local conventions. Claude switches context automatically when I cd into a different repo.
CLAUDE.md + project CLAUDE.md + rules + memories all load automatically./compact at a natural breakpoint.If I were starting from scratch:
~/.claude/rules/ persists across sessions and projects. A prompt dies when the conversation ends.rm -rf, --force, publish before you ever need to.Most of this configuration came from real mistakes — a force-push that shouldn't have happened, an npm install in a pnpm project, a session that ran out of context mid-implementation. Each rule exists because I needed it to.