7 Mental Models to Effectively Utilize Claude Code as an Agentic System
Many engineers are already using Gen AI to improve their productivity, but the real shift is from chat assistants to coding agents that can think, plan and execute. When people like Andrej Karpathy and Linus Torvalds talk seriously about this change, it is clear this is a workflow shift. We used to say software engineering is 75% thinking and 25% typing. With Claude Code that is now the default way of working. I have been using it for the last six months, completed the DeepLearning.AI and Anthropic Academy courses, and applied it to software development, data analysis and automation. One important caveat is that every iteration builds on the previous state. If you accept something that is 95% correct without fixing the 5%, the next result starts from the wrong baseline and the quality drops fast. The human must control the loop. In this article I will talk about seven mental models that will help you effectively use Claude Code.
How Claude Code Works Under the Hood
Claude Code runs locally as a CLI and uses the Claude model only to decide the next step. In each iteration it sends the current conversation, the instructions from CLAUDE.md, and the list of available tools. The model does not read the repository by itself. It asks for an action such as opening a file, searching the codebase, editing something, or running a command. The CLI executes it and returns the result. Since there is no pre indexing, a file becomes part of the context only when it is explicitly read.
All changes go through this flow. It can write only inside the project, shell commands run only after approval, and only the retrieved content is sent back to the model, so the codebase stays local. The session always starts from the project memory, and anything external is exposed as another tool through MCP and follows the same loop. So every task runs as a loop of loading the required context, taking an action, observing the result, and iterating until it converges.
How to Scope Tasks, Manage Context, and Reduce Token Usage
Context determines how much the agent has to explore before it can act. A broad prompt makes it search across the repository and load multiple files for the first step. Starting from the exact location changes that. Referring to @src/auth/login.ts for a change or @tests/payment/failure.spec.ts for a failure loads the relevant state immediately. Fewer read operations mean a shorter loop, faster convergence, and more of the token budget available for reasoning instead of exploration.
Once the session is running, the goal is to control what it carries forward. When you switch to a different problem, /clear drops the previous state completely. When the direction is correct but the history has grown, /compact keeps the summary and removes the intermediate steps so the working context stays small.
That compacted state is reusable. You can return to it with claude --resume instead of rebuilding the context, and Ctrl + R lets you quickly search past inputs when you remember you have already run something similar.
Token usage increases with every file that is opened and every response that is generated, so letting it continue in the wrong path is expensive. Stopping early with Esc prevents unnecessary context from being added. A consistent working pattern is to start from a precise entry point, compact when the plan is stable, and clear when the task changes.
How to Use CLAUDE.md as a Layered Memory System
Session context disappears. CLAUDE.md is what gets loaded at the start of every run, which means the agent begins with the project structure, conventions, and common commands already in place. It does not need to rediscover them through file reads. Anything you find yourself repeating in prompts belongs here.
The hierarchy is about specificity. Your global ~/.claude/CLAUDE.md defines personal defaults across projects, while the project CLAUDE.md holds shared architecture, workflows, and build or test commands and should be versioned with the codebase. In larger repositories this works best as modular CLAUDE.md files placed closer to the relevant code so the correct rules load only when you work in that area. This keeps the instructions relevant and avoids competing for tokens with unrelated context.
In practice this becomes an incremental system. Start with /init, keep what is useful, and whenever you correct the same behaviour twice, add it to memory with the # command instead of repeating it in prompts. So repeated instructions move from prompts into CLAUDE.md and become the default starting state.
When to Use Planning Mode and When to Use Thinking Mode
The default loop is optimized for taking the next correct step. Planning and Thinking increase the reasoning budget before execution, so both cost extra tokens. Planning mode is entered with Shift+Tab and runs as a read-only phase. It is for tasks that are wide: multi-file changes, refactors, or when the approach is not yet clear. It lets the agent explore, produce a plan, and align on the sequence before any edits.
Thinking mode, toggled with Alt/Option + T, increases reasoning depth for a single step. It is for complex logic, debugging, or cases where correctness depends on careful analysis. Using it for straightforward changes only slows the loop and increase token usage.
Because both are more expensive, they are deliberate tools. So the workflow becomes breadth with Planning, depth with Thinking, and speed with the default loop.
How to Turn Repeated Work into Commands and Skills
Commands and skills are the same reusable prompt system. The difference is how they are triggered. A command runs only when you invoke it with /, which makes it ideal for deterministic, argument-driven tasks. A skill is discovered from its description and applied automatically when the task matches its domain.
Command
A command is best when the input changes but the steps stay the same. For example, running tests and fixing failures for a specific Spring Boot module:
# .claude/commands/test-module.md
---
arguments:
- name: module
description: Spring Boot module to test
---
Run tests for {{module}}.
If any test fails:
1. Read the failing test
2. Fix the implementation
3. Re-run only the affected tests
Show the diff when all tests pass.
Usage:
/test-module module=payments
Skill
A skill is for domain behaviour that should always apply. For example, a Spring Boot API review playbook:
# .claude/skills/spring-api-review/SKILL.md
---
name: spring-api-review
description: Review Spring Boot API changes for correctness and production readiness
---
When reviewing a backend change:
1. Read the controller and service layer
2. Validate request and response contracts
3. Check transactional boundaries
4. Verify repository usage and fetch strategy
5. Ensure proper exception handling
6. Run tests for the affected module
7. Report issues in:
- Breaking changes
- Validation gaps
- Transaction risks
- Test coverage
You don’t invoke this explicitly. When you ask:
“Review this API change”
Claude loads the skill and follows the playbook.
Skills are lazy-loaded. Only the description stays in memory until the task matches, which keeps the working context small. If you want full manual control, you can disable automatic invocation and run them like commands.
So input-driven repetition becomes a command, domain expertise becomes a skill, and execution starts from a prepared workflow instead of an empty prompt.
How to Use Hooks as Automatic Guardrails
Hooks run shell commands at defined points in the tool lifecycle and are configured in .claude/settings.json (project) or ~/.claude/settings.json (global). Unlike CLAUDE.md, which guides behaviour, hooks are deterministic. They either allow an action to continue (exit 0) or block it (exit 2).
Recommended by LinkedIn
The most common workflow hook is to validate every change before the loop proceeds. In a Spring Boot project you can compile and test automatically after a file edit using a PostToolUse hook:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"command": "FILE=$(jq -r '.tool_input.file_path'); if [[ $FILE == *.java ]]; then ./mvnw -q -DskipTests=false test; fi"
}
]
}
}
Now every Java modification triggers the build. If the change breaks the application, the failure is returned immediately and the agent fixes it before moving forward.
Security rules are enforced either with permissions (to deny access completely) or a PreToolUse hook (to inspect and block a command before it runs). To prevent reading secrets:
{
"permissions": {
"deny": [
"Read(./.env*)",
"Read(./**/secrets/**)",
"Read(./**/*.pem)"
]
}
}
To stop destructive shell commands:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"command": "COMMAND=$(jq -r '.tool_input.command'); if [[ $COMMAND == *\"rm -rf\"* ]]; then echo 'Blocked: Destructive command prohibited' >&2; exit 2; fi"
}
]
}
}
Because this runs before execution, the command never reaches your system.
A SessionStart hook injects runtime context so you don’t restate it when resuming work:
{
"hooks": {
"SessionStart": [
{
"matcher": "*",
"command": "echo \"Branch: $(git branch --show-current) | Changes: $(git status --short | wc -l)\""
}
]
}
}
The output is added directly to Claude’s context.
So manual review becomes automatic enforcement, and every iteration must pass the same gates.
How MCP Turns the Loop into a Real System Interface
Built-in tools operate on local files. MCP lets the same loop call external systems through structured APIs. You add a server once with claude mcp add, and the agent can query data, read issues, or fetch documentation as part of execution without writing glue code.
claude mcp add postgres npx -y @modelcontextprotocol/server-postgres \
postgres://readonly@localhost:5432/orders
Now the database becomes a tool. In a Spring Boot service this removes the usual guesswork. Instead of reading entity classes and hoping they match production, you can say:
“Look at the users table and generate the correct repository and mybatis layer.”
Claude queries the real schema and writes the entity from the source of truth. The loop becomes:
read actual state → apply change → run tests → iterate
The same pattern applies to delivery. After connecting GitHub:
claude mcp add github npx -y @modelcontextprotocol/server-github
a prompt like:
“Summarize the PR feedback and update the service”
pulls review context directly instead of pasting it into the chat.
This power comes with the same responsibility as giving a script access to your system. MCP servers run with your user permissions, so you should only connect trusted ones, prefer read-only access for production data, and keep credentials in environment variables managed in your Claude config. More tools also mean more available context, so the same rule applies: connect what you actually use.
So external systems become structured tools, and the same loop operates on real data instead of guesses.
Claude Code becomes predictable when you design the loop instead of driving it manually. Scoped context makes it converge faster. CLAUDE.md gives every session the same starting state. Planning and Thinking spend extra reasoning only where it reduces iterations. Commands and skills start execution from prepared workflows. Hooks move quality checks into the loop. MCP lets the loop act on real systems instead of assumptions.
The compounding effect works in both directions. Weak context, unsafe access, or ad-hoc prompts degrade every step that follows. When the correct patterns are encoded, each iteration begins from a better state than the previous one. The human remains the control plane that decides what is trusted, what is remembered, and what is allowed to run.
So the advantage is not faster output. It is a loop where context is scoped, memory is layered, reasoning is allocated, execution is prepared, quality is gated, and external systems are controlled.
This article lives in