I've used Claude Code daily since it came out. Here are the best practices, tools, and configuration patterns I've picked up. Most of this applies to other coding agents (Codex, Gemini CLI) too.
TL;DR
My dotfiles, configs, and skills for Claude Code:
https://github.com/vinta/hal-9000
CLAUDE.md (or AGENTS.md)
The Global CLAUDE.md
Your ~/.claude/CLAUDE.md should only contain:
- Your preferences and nudges to correct agent behaviors
- You probably don't need to tell it YAGNI or KISS. They're already built in
Pro tip: before adding something to CLAUDE.md, ask it, "Is this already covered in your system prompt?"
Here are some key parts of my CLAUDE.md:
<prefer_online_sources>
Use the find-docs skill or WebSearch to verify before relying on pre-trained knowledge. Look things up when:
- Writing code that uses libraries, APIs, or CLI tools
- Configuring tools, services, or environment variables
- Checking if a stdlib replacement exists for a third-party package
- Pinning dependency versions — always check the latest
- Unsure about exact syntax, flags, or config format
- Making confident assertions about external tool behavior
</prefer_online_sources>
<auto_commit if="you have completed the user's requested change">
Use the commit skill to commit. Don't batch unrelated changes into one commit.
</auto_commit>
References:
- GitHub: vinta/hal-9000 - The user-level CLAUDE.md
- Stop Claude from Ignoring Your CLAUDE.md
- Claude Prompting Best Practices
The Project CLAUDE.md
For project-specific instructions, put them in the project-level CLAUDE.md.
The highest-signal content in your project CLAUDE.md (or any skill) is the Gotchas section. Build these from the failure points Claude Code actually runs into.
References:
- Twitter: @trq212 - Lessons from Building Claude Code: How We Use Skills
- GitHub: anthropics/claude-plugins-official - CLAUDE.md templates
Per File Type Rules
For language-specific or per-file rules, put them in ~/.claude/rules/, so Claude Code only loads them when editing those file types.
For instance, ~/.claude/rules/python.md:
---
paths:
- "**/*.py"
---
# Python
- When choosing a Python library or tool, search online and check https://awesome-python.com/llms.txt for curated alternatives before picking one
- Before adding a dependency, search PyPI or the web for the latest version
- Pin exact dependency versions in pyproject.toml — no >=, ~=, or ^ specifiers
- Target Python >=3.13 by default — if a project sets an explicit version (e.g. requires-python in pyproject.toml), follow that instead
- Use modern syntax: X | Y unions, match/case, tomllib
- Scripts run by system python3 must work on Python 3.9 — add from __future__ import annotations and avoid 3.10+ stdlib APIs
- Use uv for project and environment management
- uv run instead of python3 — picks up the project venv and dependencies automatically
- Use ruff for linting and formatting
- Use pytest for testing
- assert is fine in tests but use # noqa: S101 assert elsewhere
- Use pathlib.Path over os.path
- Use TypedDict for structured dicts (hook inputs, configs) — not plain dicts or dataclasses
- Use keyword-only args (*) for optional/config parameters: def run(cmd, *, shell=True)
- All # noqa comments must include the rule name: # noqa: S603 subprocess-without-shell-equals-true or # noqa: S603 PLW1510 subprocess-without-shell-equals-true subprocess-run-without-check if multiple rules
References:
Settings
If you're not using a sandbox or devcontainer, you may want to block some evil commands in your ~/.claude/settings.json.
{
"cleanupPeriodDays": 365,
"env": {
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1",
},
"permissions": {
"deny": [
"Read(~/.aws/**)",
"Read(~/.config/**)",
"Read(~/.docker/**)",
"Read(~/.dropbox/**)",
"Read(~/.gnupg/**)",
"Read(~/.gsutil/**)",
"Read(~/.kube/**)",
"Read(~/.npmrc)",
"Read(~/.orbstack/**)",
"Read(~/.pypirc)",
"Read(~/.ssh/**)",
"Read(~/*history*)",
"Read(~/**/*credential*)",
"Read(~/Library/**)",
"Write(~/Library/**)",
"Edit(~/Library/**)",
"Read(~/Dropbox/**)",
"Write(~/Dropbox/**)",
"Edit(~/Dropbox/**)",
"Read(//etc/**)",
"Write(//etc/**)",
"Edit(//etc/**)",
"Bash(su:*)",
"Bash(sudo:*)",
"Bash(passwd:*)",
"Bash(env:*)",
"Bash(printenv:*)",
"Bash(history:*)",
"Bash(fc:*)",
"Bash(eval:*)",
"Bash(exec:*)",
"Bash(rsync:*)",
"Bash(sftp:*)",
"Bash(telnet:*)",
"Bash(socat:*)",
"Bash(nc:*)",
"Bash(ncat:*)",
"Bash(netcat:*)",
"Bash(nmap:*)",
"Bash(kill:*)",
"Bash(killall:*)",
"Bash(pkill:*)",
"Bash(chmod:*)",
"Bash(chown:*)",
"Bash(chflags:*)",
"Bash(xattr:*)",
"Bash(diskutil:*)",
"Bash(mkfs:*)",
"Bash(security:*)",
"Bash(defaults:*)",
"Bash(launchctl:*)",
"Bash(osascript:*)",
"Bash(dscl:*)",
"Bash(networksetup:*)",
"Bash(scutil:*)",
"Bash(systemsetup:*)",
"Bash(pmset:*)"
],
"ask": [
"Bash(curl:*)",
"Bash(wget:*)"
]
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python3 ~/.claude/hooks/guard-bash-paths.py"
}
]
}
]
},
"statusLine": {
"type": "command",
"command": "python3 ~/.claude/statusline/run.py"
},
"enabledPlugins": {
"gh-cli@trailofbits": true,
"hal-voice@hal-9000": true,
"skill-creator@claude-plugins-official": true,
"superpowers@claude-plugins-official": true
}
}
However, "deny": ["Read(~/.aws/**)", "Read(~/.kube/**)", ...] alone is not enough, since Claude Code can still read sensitive files through the Bash tool. You can write a simple hook to intercept Bash commands that access blocked files, like this guard-bash-paths.py hook.
References:
Plugins
Claude Code Plugins are simply a way to package skills, commands, agents, hooks, and MCP servers. Distributing them as a plugin has the following advantages:
- Auto update (versioned releases)
- Auto hooks configuration (users don't need to edit their
~/.claude/settings.jsonmanually) - Skills have a
/plugin-name:your-skill-nameprefix (no more conflicts)
To install a plugin, you need to add a marketplace first. A marketplace is usually just a GitHub repo. Think of it as a namespace.
claude plugin marketplace add anthropics/claude-plugins-official
claude plugin marketplace add trailofbits/skills
claude plugin marketplace add vinta/hal-9000
# then enter Claude Code to browse plugins
/plugins
References:
Here are plugins I use:
- GitHub: anthropics/claude-plugins-official: The official Claude Code marketplace
- GitHub: anthropics/knowledge-work-plugins: Another official marketplace
- GitHub: obra/superpowers
- GitHub: trailofbits/skills
Skills
Skills can contain executable scripts and hooks, not just Markdown. Use with caution! When in doubt, have your agent review them first.
References:
Here are skills I use, mostly installed per project:
# my skills
npx skills add https://github.com/vinta/hal-9000 --skill commit magi-ex second-opinions -g
npx skills add https://github.com/vinta/dear-ai
# writing skills
npx skills add https://github.com/softaworks/agent-toolkit --skill writing-clearly-and-concisely humanizer naming-analyzer
npx skills add https://github.com/hardikpandya/stop-slop
npx skills add https://github.com/shyuan/writing-humanizer
# doc skills
npx skills add https://github.com/upstash/context7 --skill find-docs -g
# backend skills
npx skills add https://github.com/trailofbits/skills --skill modern-python
npx skills add https://github.com/vintasoftware/django-ai-plugins --skill django-expert
npx skills add https://github.com/supabase/agent-skills
npx skills add https://github.com/planetscale/database-skills
# frontend skills
npx skills add https://github.com/vercel-labs/agent-skills
npx skills add https://github.com/vercel-labs/next-skills
# design skills
npx skills add https://github.com/openai/skills --skill frontend-skill
npx skills add https://github.com/pbakaus/impeccable
npx skills add https://github.com/Leonxlnx/taste-skill
npx skills add https://github.com/ibelick/ui-skills
npx skills add https://github.com/raphaelsalaja/userinterface-wiki
# video skills
npx skills add https://github.com/remotion-dev/skills
# browser skills
npx skills add https://github.com/microsoft/playwright-cli
npx skills add https://github.com/vercel-labs/agent-browser
npx skills list -g
npx skills update -g
npx skills remove --all -g
Highlights:
/brainstormingfrom superpowers: When in doubt, start with this skill/writing-skillsfrom superpowers: Use this skill to improve your skills/skill-creatorfrom claude-plugins-official: Use this skill to evaluate your skills/frontend-designfrom impeccable: The better version of the official/frontend-designskill/office-hoursfrom gstack: The heavy version of/brainstorming! (it collects usage telemetry, so remember to say no)/simplify: Run it often, you will like it/insights: Analyze your Claude Code sessions
You can find more skills on skills.sh.
MCP Servers
You probably don't need any MCP servers if you can do the same thing with CLI + skills.
Playwright MCP
No, you should use the playwright-cli or agent-browser skill instead.
npm install -g @playwright/cli@latest
npm install -g agent-browser
agent-browser install
References:
GitHub MCP
No, you should use the gh command instead.
brew install gh
Trail of Bits' gh-cli plugin is also worth a look, though you should check how it uses hooks to intercept GitHub fetch requests. Quite controversial for a security company.
References:
Codex MCP
Yes, ironically. Other coding agents like Claude Code can use Codex via MCP, which is slightly more stable than invoking it with codex exec via CLI.
# Codex reads your local .codex/config.toml by default
claude mcp add codex --scope user -- codex mcp-server
# You can still override some configs
claude mcp add codex --scope user -- codex -m gpt-5.3-codex-spark -c model_reasoning_effort="medium" mcp-server
References:
Some Other Tips
Prompt Best Practices
Command Aliases
# in ~/.zshrc
alias cc="claude --teammate-mode tmux"
alias ccc="claude --continue --teammate-mode tmux"
alias cct='tmux -CC new-session -s "claude-$(date +%s)" claude --teammate-mode tmux'
alias ccy="claude --teammate-mode tmux --dangerously-skip-permissions"
ccp() { claude --no-chrome --no-session-persistence -p "$*"; }
Use ccp for ad-hoc prompts:
ccp "commit"
ccp "list all .md in this repo"
References:
Customize Your Statusline
Claude Code has a customizable statusline at the bottom of the terminal. You can run any script that outputs text.
Mine shows the current model, the current working folder, the git branch, and a grammar-corrected version of my last prompt (because my English needs all the help it can get). The grammar correction runs an ad-hoc claude command inside the statusline script.

References:
Run Ad-Hoc Claude Commands Inside Scripts
You can invoke claude as a one-shot CLI tool from hooks, statusline scripts, CI, or anywhere else. The trick is using the right flags to get a clean, isolated call with zero side effects:
cmd = """
claude
--model haiku
--max-turns 1
--setting-sources ""
--tools ""
--disable-slash-commands
--no-session-persistence
--no-chrome
--print
"""
result = subprocess.run(
[*shlex.split(cmd), your_prompt],
capture_output=True,
text=True,
timeout=15,
cwd="/tmp",
)
What each flag does:
--setting-sources "": don't load hooks (avoids infinite recursion if called from a hook)--no-session-persistenceandcwd="/tmp": avoid polluting your current context--tools "": no file access, no bash, pure text in/out--no-chrome: skip the Chrome integration
Multi-Model Second Opinions
You can get independent code reviews or brainstorming input from other model families (Codex, Gemini) without leaving Claude Code. I have two skills for this:
magi-ex: Evangelion's MAGI system as a brainstorming panel. Three personas (Scientist/Opus, Mother/Codex, Woman/Gemini) deliberate in parallelsecond-opinions: Asks Codex and/or Gemini to review code, plans, or docs, then synthesizes their feedback
This works because each model family has different training biases. Claude might miss something Codex catches, and vice versa. It's especially useful for architecture decisions and "what should I build next" brainstorming.
References: