Most Claude Code tutorials stop at “install it and start chatting”. That gets you maybe 20% of what the tool does. The other 80% comes from understanding how context, modes, subagents, and hooks
fit together. It’s the stuff that’s technically in the docs but reads as marketing until you’ve burned a few thousand tokens learning it the hard way.
This is what I’d tell a teammate on day one if I had ten minutes. Patterns that change how fast you actually ship, and a few that will save you from yourself.
What Claude Code is, briefly
Claude Code is Anthropic‘s CLI agent. You run claude in a terminal, and it can read files, run shell commands, edit code, and call tools. There are extensions for VS Code and a desktop app. The CLI is where the interesting features live.
The mental model that matters: it’s a junior engineer who usually forgets things. Vague input gets vague output. Specific input (file paths, constraints, what you’ve ruled out, what “done” looks like) gets results you don’t have to redo.
Context and cache mechanics
This is probably the biggest lever on cost and latency, and almost nobody who hasn’t used the API understands it.
The prompt cache has a 5-minute TTL. When you send a message, Anthropic caches the prefix of your conversation. If your next message comes within 5 minutes, the cached prefix is essentially free. If you step away for a meeting and come back 20 minutes later, the entire conversation is re-read from scratch, uncached. Slower, more expensive.
Practical implication: if you’re about to step away, finish your turn at a clean boundary. Don’t leave a half-finished plan dangling. The next reply will replay the whole thing.
There’s an extended 1-hour cache too, but it’s opt-in. Default is 5 minutes.
/compact accepts instructions
Plain /compact summarizes your conversation and replaces the full history with the summary. It’s lossy, and the default summarization will often drop the wrong things. Better:
/compactpreserve the auth refactor decisions and the failing test output, drop the file listings
You’re telling Claude what matters before it summarizes. Use it before context gets tight, not after.
/clear isn’t /compact
/clear wipes the conversation entirely. Use it when switching topics. Starting a new task with a clean slate keeps later prompts fast and prevents earlier wrong turns from biasing the answer. /compact summarizes. /clear resets.
Context drifts
If Claude went down a wrong path and you corrected it, that wrong path is still in the conversation, still affecting what it pattern-matches on. For non-trivial pivots, /clear and restart with what you learned. Hoping it “remembers the correction” gets unreliable past a certain point.
Resuming sessions
claude --resume lists your past sessions in the current project and lets you pick one up. Each session is stored as a .jsonl file under ~/.claude/projects/. Useful when coming back to a stalled task with full history intact.
Modes: plan, edit, accept-edits
Shift+Tab cycles between modes in an active session.
Plan mode is read-only. It can read files, grep, run safe shell commands, but it can’t write or edit. This is the mode you want for anything you don’t fully understand yet. It forces investigation before code gets touched. When the plan looks right, Shift+Tab back to edit mode and execute.
People underuse plan mode because muscle memory says “just ask and let it do it”. That works for trivial changes. For anything load-bearing, ten minutes in plan mode saves an hour of unwinding bad edits.
Accept-edits mode auto-accepts file edits without prompting per change. Good for refactors where you’ll review the full diff at the end anyway. Pair it with frequent git diff checks. You get the speed of unattended editing without losing the ability to catch a bad change before it compounds.
Thinking budgets
Claude Code supports keyword-triggered extended thinking. The keywords escalate:
thinkis a small budgetthink hardis largerthink harderis larger stillultrathinkis the maximum
Use these for architectural decisions, hard debugging, or anything where Claude gave you a confidently wrong answer on a subtle question. Don’t use them for simple tasks, such as “rename this variable”. You’re paying for thinking tokens that don’t change the outcome. Some tasks fail without thinking. Most don’t need it. You learn the difference by trying a hard task without it and seeing where it breaks.
Subagents protect your main context
The Agent tool spawns a subagent that works in isolation. It has its own context window. When it finishes, you get a summary back, not the full transcript.
This matters because some operations bloat your main context badly. A large grep across the repo. Reading several files to find one piece of information. Web research with multiple page fetches. Big find commands that dump thousands of paths.
Delegating those to an Explore or general-purpose subagent keeps your main thread clean. You get the answer.
A couple of patterns that pay off here.
- Parallel subagents: if you have three independent questions, launch three subagents in one message. They run concurrently. Sequential launches are wasted time.
- Trust but verify: the agent’s summary is what it intended to do. If it claims it edited files, run git diff and check. Subagents will sometimes report success on a partial implementation. Treat the report as a hypothesis, not a fact.
Input shortcuts that change the workflow
Three small features most people miss.
! runs a shell command directly in the conversation. Output lands in context. Useful for interactive things you’d otherwise have to switch terminals for:
! gcloud auth login! git log --oneline -20
The shell output becomes part of the conversation, so Claude can act on it immediately.
@path/to/file pulls the file into context inline. You don’t have to ask Claude to read it. Handy when referencing a specific file in your prompt:
Refactor @src/auth/session.ts to use the new token format from @src/auth/tokens.ts
# prefix quick-saves the line to a CLAUDE.md. It prompts you to pick which one (project, user, or local). Catch yourself repeating an instruction? Save it once.
# never edit files under generated/# this project uses pnpm, not npm
These three together cut a huge amount of friction out of normal use.
The CLAUDE.md hierarchy
CLAUDE.md files auto-load as context every session. The hierarchy:
~/.claude/CLAUDE.mdis user-level. Loads in every session everywhere./CLAUDE.mdloads in this project./CLAUDE.mdloads when you’re working inside that directory.
Use the hierarchy. Module-specific belongs in src/payments/CLAUDE.md, not the project root. Personal preferences (“I always want explanations in terms of TypeScript analogies”) belong in your user-level file, not committed to the repo.
The best use of CLAUDE.md is for the things you find yourself explaining twice. Example:
- Use the existing logger, don’t import a new one.
- Tests live in tests/, not next to the source.
Save it once, never explain it again.
Custom slash commands
If you paste the same prompt twice, make it a slash command. Drop a markdown file in .claude/commands/. Example:
.claude/commands/changelog.mdGenerate a changelog for the commits since the last release tag. Group by feat / fix / chore. Include PR numbers where present.
Now /changelog runs that prompt. Commit .claude/commands/ to your repo, and your team gets them too.
A few worth having: /review for code review of pending changes, /explain to explain a file or function in plain English, /test to write tests for the current changes. You might also use skills, but command is the simplest form, use skills only when you need to run scripts.
Hooks for “always do X”
Memory and CLAUDE.md are read by Claude, not enforced by the harness. If you want a behavior that always happens, regardless of what Claude decides, that’s a hook.
Hooks live in settings.json and trigger on events:
PreToolUseruns before a tool call. Can block it.PostToolUseruns after. Can react.Stopruns when Claude finishes a response.UserPromptSubmitruns when you submit a prompt.
What people actually do with them, for example:
- A
Stophook that runsnpm run lintafter every response. - A
PreToolUsehook that refuses anyrm -rfoutside/tmp. - A PostToolUse hook that auto-formats edited files.
If you’ve ever told Claude “always run tests after editing” and it forgot two responses later, that’s a hooks problem, not a memory problem.
Switching models mid-session
/model swaps the model for the current conversation. Use it.
The common pattern is Opus for design, debugging, and the hard reasoning bits, then Sonnet for high-volume edits where speed matters more than depth. You don’t need Opus to update a hundred import paths.
Most people pick one model at session start and never switch. Matching the model to the phase of work is one of the easier wins available.
Worktrees for parallel work
Git worktrees let you check out multiple branches of the same repo into separate directories. With Claude Code, that means multiple sessions on different branches without stomping on each other.
git worktree add ../task-manager-feature-x feature-xcd ../task-manager-feature-xclaude
Run a second claude from your main worktree on a different branch. Two sessions, two branches, one repo.
The Agent tool also accepts isolation: “worktree”, which sandboxes a subagent’s work in its own worktree. Useful when you want an agent to attempt a risky change without touching your working tree until you’ve reviewed it.
Prompt quality matters more than model choice
This is the most underrated thing about getting good output.
Compare:
- “Fix the session bug”
- “Fix the bug in src/auth/session.ts:142 where expiresAt is set in seconds but compared in ms”
The second one will get the right fix from any model. The first will get speculation, even from the smartest one. Two prompt patterns that work. Telling Claude what not to do is often higher leverage than telling it what to do:
Don’t refactor surrounding code, don’t add tests, don’t touch the migration. Only change the bug on line 142.
Without that, you’ll often get a “while I was in there” cleanup pass that adds noise to your diff. For exploratory questions, ask for a recommendation with the tradeoff, not a plan. “How should we approach X?” answered as a recommendation gets you a useful starting point. Answered as a plan, you get premature commitment to a path before you’ve decided it’s the right one.
Verify before claiming done
The most common failure mode is “should work” or “looks correct” without actually running it.
Type checks and unit tests verify code, not feature behavior. If you changed UI, open the browser. If you changed an endpoint, hit it. If you changed a script, run it.
When Claude reports a task as complete, the safe move is to ask what it actually ran to verify. If the answer is “I read the code”, that isn’t verification.
If you don’t want to remember all of this
AI DevKit is a Claude Code setup that bakes these patterns into skills and hooks. The right thing happens automatically, so you don’t have to remember.
A few of the skills line up directly with sections from this post.
The verify skill auto-triggers when Claude claims a task is done. It runs the verification step Claude was about to skip.
The dev-lifecycle skill walks a feature from idea to merged code: requirements, clarification, design review, TDD-style planning, implementation, tests, code review. At every phase, it forces you to spell out the goal, the constraints, and what done looks like before Claude writes anything. You can’t skip ahead with a half-formed plan.
The debug skill kicks in when you’re chasing a bug. It runs Claude through a real RCA: reproduce, isolate, hypothesize, then verify the fix.
The document-code skill documents code without your guiding function by function.
Beyond the skills, AI DevKit adds a few things to the harness.
A local memory service, for the long-term memory CLAUDE.md can’t do. CLAUDE.md is a static file you maintain. The memory service learns across sessions, so Claude stops making the same mistake twice in different conversations.
An orchestration layer for running multiple Claude Code in parallel. Worth it once you are trying to run many agents at the same time.
Telegram integration, so a long-running agent can ping you when it needs input or hits a blocker. Frees you from babysitting the terminal.
If my sharing resonates with you, subscribe to my blog. I share what I learn while building real systems with AI in the loop. You can also follow me on X or Threads for more thoughts and ongoing experiments.
Discover more from Codeaholicguy
Subscribe to get the latest posts sent to your email.