How I Set Up Claude Code as My Daily Development Companion
A walkthrough of Claude Code from the ground up — what it is, how configuration scopes work, and the rules, plugins, hooks, auto memory, and CLI glue that make it click for day-to-day engineering work.
Author
Henry Chen
Published
14 April 2026
Reading
18 min read
Updated
Apr 2026
AIHow I Set Up Claude Code as My Daily Development Companion · 2026
Claude Code is the tool I spend more time in than any IDE — Rust one hour, Python the next, TypeScript the hour after that. Hundreds of messages a day, across four or five projects. Over the past few months the configuration around it has turned into something much more than autocomplete: it enforces conventions, remembers context between sessions, and drives real infrastructure on my behalf. This post walks through that setup from the ground up. If you've never opened Claude Code before, the first half is for you. If you have, skip to the configuration sections.
What Claude Code Actually Is
Claude Code is Anthropic's official CLI. You run claude in a terminal and it opens an interactive agent that can read files, edit code, execute shell commands, search the web, talk to MCP servers↗︎, and delegate work to specialized subagents — all rooted in the directory you launched it from.
Under the hood it's the same Claude model that powers the API. What sets it apart from a chat window is everything around the model: tools, permissions, hooks, memory, plugins. The model is fixed; the shell around it is what you tune.
The mental model I use: Claude Code is a shell for an agent. The agent is smart. The shell is what you configure.
Where Configuration Lives
Four scopes, higher-priority locations winning on conflict:
Scope
Location
Affects
Shared?
Managed
OS-level policy directory
All users on the machine
IT deploys
User
~/.claude/
You, across every project
No
Project
.claude/ + CLAUDE.md at repo root
Everyone in the repo
Yes (git)
Local
.claude/settings.local.json
You, in this repo only
No (gitignored)
Everything below fits somewhere on this ladder. A rule that applies to every project goes in user scope. A convention that only makes sense in this repo goes in project scope. A machine-specific override — a local path, a personal API key — goes in local scope. Managed is how organisations deploy company-wide policies that individuals can't override.
The separation matters more than it sounds. User-scope rules are how you stop repeating yourself. Project-scope rules are how you teach Claude what's non-obvious about this codebase without bloating every other session with it.
The Global Layout
My user-scope directory looks like this:
~/.claude/├── CLAUDE.md # Global instructions, loaded every session├── settings.json # Permissions, hooks, plugins, status line├── rules/ # Topic-scoped instruction files├── skills/ # Custom workflows triggered by /commands├── projects/ # Per-project auto memory (managed by Claude)│ └── <project>/memory/│ ├── MEMORY.md│ └── ...├── statusline-command.sh # Custom status bar script├── update-pricing.sh # Daily Anthropic pricing fetcher└── cache/ └── model-pricing.env
The rest of the post walks through each of these in turn, roughly in the order you'd set them up yourself.
CLAUDE.md — Instructions
This is the file Claude reads at the start of every session. Think of it as a standing briefing: who you are, what you're working on, which conventions to respect.
You can have one at ~/.claude/CLAUDE.md (applies everywhere), one at ./CLAUDE.md or ./.claude/CLAUDE.md at the root of each repo (applies only there), and a personal ./CLAUDE.local.md that stays out of git. All discovered files are concatenated into context — they don't override each other. If you're starting a new project, /init inside Claude Code generates a first draft by reading your codebase.
Mine keeps the global version short. It's an index, not a manual:
Who I am — full-stack developer, Rust / C# / .NET / Python / TypeScript.
How I work — macOS host plus a Windows VM through Parallels for the .NET Framework 4.8 projects.
Behaviour — explore before editing, ask before assuming, match the existing style, never force-push main.
Pointers to rules — each domain has its own file under rules/.
The reason for keeping it short is that wall-of-text system prompts get ignored, both by the model and by future me when I go to edit it. The docs themselves recommend under 200 lines per CLAUDE.md. An index tells Claude where to look and keeps the actual content close to where it's relevant.
You can also pull in other files with @path imports — useful for referencing a README, a package.json, or a shared rules file from your home directory. Imports resolve recursively, so a project CLAUDE.md can pull in a personal preferences file without duplicating it.
Project-level CLAUDE.md files carry the things that are specific to a given codebase — the package manager, the content model, import aliases, testing commands. My personal website's looks something like:
Use pnpm (not npm).
Blog posts are MDX files under content/blog/.
Imports use @/i18n/navigation (not next/link).
API responses follow the global RFC 9457 rules.
cd into a different repo and the project-scope CLAUDE.md loads automatically, layered on top of the global one. Claude never needs to be re-briefed.
Rules — Scoped, Reloadable Standards
Claude Code has a dedicated directory for modular instructions: .claude/rules/ at the project level and ~/.claude/rules/ at the user level. Every .md file in there is discovered recursively and loaded alongside CLAUDE.md. It's a built-in feature, not a convention you have to bolt on.
The thing that makes rules genuinely useful over just extending CLAUDE.md: you can scope a rule to specific files via frontmatter. A rule with paths: ["src/api/**/*.ts"] only enters context when Claude is actually working on an API file. The rest of the time, it stays out of the way.
My user-level rule set is ten files, each focused on a single concern:
File
What it covers
coding-style.md
One concept per file, functions under 50 lines, "why" comments
RFC 9457 errors, cursor pagination, rate-limit headers on all paths
Two things make this worth the setup effort:
Rules survive compaction. Anything Claude picks up mid-conversation is at risk when the context window is summarised. Project-root CLAUDE.md and .claude/rules/ files are re-injected from disk after compaction.
They're diffable. When I change a standard, I change one file — not four prompts scattered across my shell history.
The payoff shows up in small ways every day. Claude runs cargo clippy before Rust commits, reaches for uv instead of pip, formats API errors in RFC 9457 shape — without me saying a word. Write the rule once, stop repeating yourself.
settings.json — Permissions, Hooks, Plugins, Status Line
settings.json is the other half of the global config. It controls what Claude is allowed to do and what happens around its actions. Four things live here, each big enough to earn its own section.
Permissions — Defense in Depth
Permissions split cleanly into an allow-list (auto-approved, no prompt) and a deny-list (hard-blocked, no override).
Allowed — what I want Claude to do without asking:
File operations: Read, Edit, Write, Glob, Grep
Shell: Bash, scoped by the deny-list
Web: WebFetch, WebSearch
Every tool from Playwright and Context7
Denied — things that should never run, even if the model thinks they should:
The deny-list is the single highest-leverage thing you can configure. A model that occasionally hallucinates dangerous commands is fine if those commands can never actually run. Set this up before you need it, not after.
For finer control, permissions accept argument-shape patterns — Bash(gh pr *) instead of opening Bash wholesale for gh. I use this when I want a CLI available but not trusted with arbitrary subcommands.
Hooks — Automated Guardrails
Hooks run shell commands around Claude's tool use. The docs list more than twenty events — PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, Stop, PreCompact, PostCompact, SubagentStart, FileChanged, and more. Each receives a JSON payload on stdin and can return structured output to block, modify, or just observe the call.
I use three of them.
A PreToolUse hook that nudges me before any Bash call:
The matcher field is a tool name, a |-separated list, or a regex. PreToolUse can also block a call by returning {"hookSpecificOutput": {"permissionDecision": "deny"}}, which is how organisations enforce policy that goes beyond the static deny-list.
A PostToolUse hook that reminds Claude to lint after every edit. The payload arrives on stdin, so I extract the file path with jq:
FILE=$(jq -r '.tool_input.file_path // empty')case "$FILE" in *.rs) echo "Reminder: run cargo clippy" ;; *.cs) echo "Reminder: run dotnet build" ;; *.py) echo "Reminder: run ruff check && ruff format" ;;esac
Neither blocks the call — they just tap Claude on the shoulder. But they catch more than you'd think, because the reminder fires every time, not just when Claude remembers to ask.
A SessionStart hook gives me a moment to dump custom context — git status, branch staleness, a reminder about any in-flight experiment — into the very first message.
Plugins and Marketplaces
Plugins package skills, agents, hooks, MCP servers, and slash commands into a single installable unit. Claude Code ships with the official Anthropic marketplace (claude-plugins-official) already active, and you can add third-party marketplaces from GitHub repos, Git URLs, or local paths.
Adding a third-party marketplace automatically happens through /plugin marketplace add, but you can also declare it in settings.json so teammates who trust the repo get prompted to install it:
I keep a plugin-to-task mapping in rules/agents.md so Claude reaches for the right tool without being asked:
Task
Plugin
Plan a feature
/feature-dev or Plan mode
Review code or PR
/code-review
Simplify code
/simplify
Git commit
/commit-commands:commit
Commit + push + PR
/commit-commands:commit-push-pr
Rust diagnostics
rust-analyzer-lsp
Browser testing
playwright
Platform CLIs
Several of those plugins (github, vercel, supabase, context7, playwright) are really MCP servers in a wrapper — they query APIs and hand back structured data, which is good for reading state. For actually doing things — shipping a deploy, running a migration, cutting a release — I let Claude call the platform's native CLI through Bash.
The ones I use most:
gh — creating PRs, polling CI, merging. /ship is essentially a scripted sequence of gh calls.
Supabase CLI — db diff, migrations, edge function deploys. The Supabase MCP handles introspection; the CLI handles changes.
Vercel CLI — vercel deploy, env pull, log tailing. The plugin tells Claude what's going on; the CLI lets it act.
AWS CLI — bucket listings, log tails, EC2 describes. IAM stays in charge of what's actually allowed.
gcloud / kubectl / docker — same story in their respective worlds.
No extra wrapping involved. The commands go through Bash, so the deny-list already blocks --force and the other destructive flags, and the PostToolUse hook still fires before anything mutating runs. When I want tighter control I allow-list a specific pattern like Bash(gh pr *) instead of opening up gh across the board.
The split I've settled on: MCP for reading, CLIs for writing, plugins for workflows that need both. Once that's written into the rules, Claude stops second-guessing which tool to reach for.
Status Line — Real-Time Dashboard
My favourite customisation. One line at the bottom of the terminal, showing everything that matters:
Left to right: model, project directory, Git branch, tokens in and out, context usage with a colour code (green under 50%, yellow 50–75%, red above 75%), session cost in USD, session duration, Git diff stats.
Cost comes from a cached copy of Anthropic's pricing, refreshed daily by a small script that scrapes the public pricing page and writes per-model rates to ~/.claude/cache/:
No API key involved. The colour-coded context bar is what I actually watch — it tells me when to /compact before the window fills up.
Auto Memory — Cross-Session Learning
Rules and CLAUDE.md are static: you write them, Claude reads them. Auto memory is dynamic, and it's a built-in feature as of Claude Code v2.1.59. Claude takes its own notes during a session — build commands it figured out, corrections you made, architecture patterns it learned — and saves them to ~/.claude/projects/<project>/memory/ as plain markdown files.
The directory contains a MEMORY.md entrypoint plus any number of topic files Claude creates as needed:
~/.claude/projects/<project>/memory/├── MEMORY.md # Index, loaded into every session├── user-profile.md # Role, preferences, expertise├── feedback.md # Corrections and confirmed approaches├── architecture.md # Decisions worth remembering└── references.md # Pointers to external systems
At session start, the first 200 lines (or 25 KB) of MEMORY.md get loaded automatically. Everything else loads on demand when Claude decides it needs the detail. The whole thing is plain markdown — you can read, edit, or delete entries directly, or open the directory via /memory inside a session.
My additions on top of the built-in behaviour:
A conventional entry format. Every memory file has YAML frontmatter (name, description, type) so the MEMORY.md index stays scannable and future Claude knows what each file is for.
Four categories.user (identity, preferences), feedback (corrections), project (architecture decisions), reference (pointers to external systems). This is just a convention encoded in my global CLAUDE.md, but it keeps the directory organised instead of turning into a pile.
Explicit permission to update. A rule in CLAUDE.md that says "when you learn something worth keeping, write it to auto memory" — because the default behaviour is conservative.
In practice this means Claude already knows I'm a native Chinese speaker who prefers terse replies, that my Efision project uses a 5-layer Clean Architecture with Service<R> generics, and that running npm inside a pnpm project is a mistake I've corrected before. These details compound. Over months they change how Claude approaches every task.
The one bit of discipline that makes memory work: don't try to front-load it. Let it build from real corrections. A memory written because the model actually got something wrong is load-bearing; one written preemptively is noise.
Custom Skills — Repeatable Workflows
Skills are Claude Code's unit for reusable workflows. Each one is a directory under ~/.claude/skills/ (or a project's .claude/skills/) containing a SKILL.md file and any supporting assets. The frontmatter tells Claude when to use it, and the markdown body tells it how.
A minimal skill:
---name: deploydescription: Deploy the application to productiondisable-model-invocation: trueallowed-tools: Bash(gh *) Bash(vercel *)---Deploy $ARGUMENTS to production:1. Run the test suite2. Build the application3. Push to the deployment target4. Verify the deployment succeeded
A few frontmatter fields I use often:
disable-model-invocation: true — "only the user can call this". Use for workflows with side effects, so Claude never auto-triggers a deploy because the code looks done.
allowed-tools — grants the skill permission to run specific tools without prompting while it's active.
context: fork with agent: Explore — runs the skill in a subagent's isolated context, good for research tasks that shouldn't pollute the main conversation.
The one I use most is /ship. One command, working tree to merged PR:
Test — run the project's test suite; auto-fix up to two times if tests fail.
Commit — stage, generate a conventional commit message from the diff.
PR — create branch, push, open PR with summary and test plan.
CI — poll gh pr checks every 30 seconds (10-minute timeout); on failure, read logs, fix, push, retry up to two times.
Merge — squash merge, delete branch, report the PR URL.
No scripting. Claude just follows the markdown and stops to ask if something breaks. It replaces what used to be five to ten manual commands.
I also have a deep-research skill — eight steps that turn a vague question into a structured report, with sources tiered by authority and intermediate artifacts saved to ~/Downloads/research/<topic>/. It's the skill equivalent of a lab notebook.
Plugin skills live inside plugins and are invoked with the namespaced form: /interface-design:audit, /commit-commands:commit-push-pr. Your own skills under ~/.claude/skills/ use the plain form: /ship, /deep-research.
A Typical Session
With everything above in place, a day looks like this:
I open Claude Code in a project. The status line immediately shows model, branch, cost, context usage.
Global CLAUDE.md, project CLAUDE.md, rules, auto memory, and plugin skills all load automatically.
I describe what I need. Claude reads the relevant code first (that's a rule), asks if something's unclear, then builds.
Hooks fire on every edit — linter reminders, push confirmations.
When the context bar turns yellow, I /compact at a natural breakpoint. Root-level rules and CLAUDE.md re-inject from disk automatically.
Bigger features get Plan mode or parallel subagents.
Anything worth carrying into the next session gets written to auto memory.
Nothing about this feels like operating an AI. It feels like pair programming with someone who has already read the code, already knows my preferences, and has opinions about which tool to use.
What I'd Set Up First
If you're starting from nothing and want the biggest return per hour of setup, in order:
Write the deny-list. Block rm -rf, --force, publish, curl | bash before you ever need them blocked.
Write a global CLAUDE.md. Keep it short — under 200 lines. Identity, working style, a few behavioural rules.
Externalise your conventions into .claude/rules/. Anything you've typed into a chat twice deserves a rule file. Use paths frontmatter to scope rules that only apply to certain parts of the tree.
Add a PostToolUse linter reminder. One-liner, catches real issues.
Customise the status line. Once you can see cost and context in real time, you work differently — you compact earlier, you notice runaway sessions.
Install the plugins your infrastructure actually uses./plugin install github@claude-plugins-official alone pays for itself in a week.
Let auto memory build itself. Don't front-load. Correct Claude when it's wrong, and those corrections stick.
Layer your config. Global for universal standards, project for local conventions, local for machine-specific quirks.
Most of my 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. Every rule in the file exists because I once needed it to.
References
Every link below is a page I consulted while writing this post. The notes are what you'll actually get from each — not just the page title.
Settings↗︎ — The canonical reference for the four configuration scopes and every field in settings.json. Start here if you're setting things up from scratch.
Memory↗︎ — Covers both halves of Claude Code's memory story: CLAUDE.md loading order, .claude/rules/ with paths frontmatter, and how the built-in auto memory directory is stored and re-loaded.
Hooks↗︎ — Full event catalogue (more than twenty), matcher regex syntax, and the JSON I/O contract for command / http / prompt / agent handler types. Essential if you want hooks that do something rather than just print reminders.
Skills↗︎ — Frontmatter fields, $ARGUMENTS substitution, inline shell-exec blocks, and context: fork for running a skill inside a subagent. Read this before writing anything beyond a trivial .
Model selection, context budget, compaction strategy
agents.md
When to delegate to subagents, parallel execution, plugin-to-task mapping
/command
Plugins↗︎ and Plugin marketplaces↗︎ — Plugin structure, manifest schema, and the /plugin install <name>@<marketplace> flow. The second link is the one that actually shows you how extraKnownMarketplaces works.
Subagents↗︎ and MCP↗︎ — When you're ready to think about Claude Code as an orchestrator rather than a single agent: subagent delegation, preloaded skills, and connecting external tools through Model Context Protocol.