Claude Code: The Complete Developer's Guide to Agentic Coding

Claude Code: The Complete Developer's Guide to Agentic Coding

The complete developer guide to Claude Code CLI: agents, subagents, skills, MCP, settings, models, and the workflows that make it production-ready.

By Omar Flores

You paste an error into a chat window. Get an answer. Paste the relevant code back in. Get another answer. Apply the fix manually. Discover the fix broke something else. Start over. This is the loop most developers have been living in — the copy-paste-verify loop — and it has been eating hours that should go toward building things.

Claude Code does not speed up that loop. It eliminates it.

When Anthropic built Claude Code, they did not build a smarter chatbox. They built a coding agent that can read your filesystem, run your tests, execute shell commands, read the output, and decide what to do next — all inside a single session, without you acting as the messenger. The model operates in what the docs call the agentic loop: plan, use tools, observe results, revise the plan. You stop being the intermediary between the AI and the codebase. You become the director.

This guide covers everything that matters: the context window, the memory hierarchy, model selection and effort levels, subagents and skills, MCP integrations, agent teams, CI/CD usage, and the session patterns that distinguish productive Claude Code work from expensive, confused Claude Code work.

The Agentic Loop, Explained

The core mental model is simple. Claude Code is not just a language model — it is a language model with tools. Those tools include reading files, writing files, running bash commands, searching the codebase with grep and glob, and calling external MCP servers. At each turn in a session, Claude decides which tool to use, uses it, reads the result, and continues.

This loop has a critical implication: Claude Code sees the actual state of your code, not what you described to it. When you ask it to fix a failing test, it reads the test file, runs the test runner, reads the output, finds the source of the failure, edits the file, and runs the tests again. You can watch this happen in real time.

The practical boundary of the loop is the context window. Everything in Claude’s working memory — file contents, conversation history, tool results — lives inside that window. When it fills up, the session degrades. Understanding this one constraint shapes every best practice in this guide.

Before a session starts, Claude reads all CLAUDE.md files it can find in your project hierarchy — from the current directory up through your home directory. That’s your memory system, and it’s where we start.

Your Memory Hierarchy

Every Claude Code session begins with a memory load. Before responding to your first message, Claude reads configuration from multiple layers: project settings, local overrides, and CLAUDE.md files walking up the directory tree.

The CLAUDE.md file is your primary tool for persistent context. Think of it as the briefing document Claude reads every morning before starting work on your codebase. The project root CLAUDE.md is for everyone — team conventions, stack details, development commands, things-to-never-do.

A useful CLAUDE.md for a backend project looks like this:

# Project: Payments API (Go)

## Stack

- Go 1.22, PostgreSQL 14, Redis 7
- Framework: standard library + chi router
- Testing: testify + httptest

## Development commands

- `make test` — run unit tests
- `make test-integration` — requires Docker running
- `make lint` — golangci-lint

## Conventions

- Use `errors.As()` for error wrapping, never `fmt.Errorf` with %v
- Database migrations live in `/migrations`, numbered sequentially
- Never commit .env files — use .env.example as the template

## Current focus

- Refactoring the subscription billing module (see `/internal/billing/`)

Claude reads this before every session. It costs context — but it pays back more than it costs when Claude respects the conventions without being reminded every time.

For larger projects, the .claude/rules/ directory lets you break memory into topic-specific files. A rule file at .claude/rules/api.md with globs: ["src/api/**"] loads only when you’re working inside the API directory. This keeps your Go service patterns out of the Flutter section and vice versa. It also means the mobile team’s conventions don’t pollute the backend team’s context.

Claude Code also supports a rules/ subdirectory under .claude/ for shared project rules — Markdown files that get loaded conditionally based on file paths. This is the right tool for monorepos with multiple languages or teams.

Mastering the Context Window

The context window is the single most important constraint in a Claude Code session. Ignoring it explains why some sessions produce great results while others spiral into confusion — Claude starts contradicting earlier decisions, forgetting patterns it applied ten minutes ago, doing redundant work.

Claude Code loads context in layers at startup: CLAUDE.md files, settings, and conversation history. Tool results, file contents, and command output accumulate as you work. The standard context window is large, and Opus and Sonnet have 1M token variants for very large codebases.

When the window fills up, Claude Code compacts the session automatically. It creates a summary of everything that happened, replaces the history with that summary, and continues from there. You lose granular history but keep the essential state. Running /compact manually gives you control over when this happens — compacting after a major phase is complete, rather than waiting until the session degrades.

Two commands give you visibility into context state:

  • /context — shows what’s currently loaded and how much of the window it occupies
  • /clear — wipes the conversation history entirely, leaving only memory files loaded

The practical rule: each session should have a clear scope. A session that starts with “review the authentication system,” then pivots to “fix the CI pipeline,” then asks about database schema optimization is not three sessions — it is one expensive, increasingly unfocused session. Use /clear to start a new task with a clean slate. The CLAUDE.md context persists; the conversation history does not.

Choosing the Right Model

Claude Code ships with model aliases that abstract away specific model version names. The aliases that matter day-to-day:

AliasWhat it does
sonnetClaude Sonnet — fast, capable, the daily workhorse
opusClaude Opus — strongest reasoning, highest cost
haikuClaude Haiku — fastest, lightest, best for simple tasks
opusplanOpus for planning, Sonnet for execution
bestBest available model at any given time
sonnet[1m]Sonnet with 1M token context window
opus[1m]Opus with 1M token context window

Switch models inside a session with /model sonnet, or set a default in your settings.json.

Beyond model selection, you control how hard the model thinks through effort levels: low, medium, high, xhigh, and max. Claude Opus 4.7 defaults to xhigh and uses adaptive reasoning — it allocates thinking tokens dynamically based on task complexity rather than burning a fixed budget on every response. The model decides which steps warrant deep reasoning and which do not.

Set the effort level at startup or in your settings:

# Start with high effort for architecture work
CLAUDE_CODE_EFFORT_LEVEL=high claude

# Or set persistently in settings.json
{
  "effortLevel": "high"
}

For complex architecture decisions, debugging across multiple systems, or any work where a wrong turn costs significant time, run with high or xhigh. For routine tasks — writing a test for a function you just described, generating boilerplate from an established pattern — medium saves time and cost without meaningful quality loss.

The opusplan alias deserves specific mention. It runs the planning phase with Opus (maximum reasoning depth), then executes the implementation steps with Sonnet (faster, cheaper). You get Opus-quality architectural thinking at a fraction of Opus-only cost. For large feature work that requires both strong planning and significant file editing, this is often the right default.

Settings and Permissions

Claude Code uses a four-level settings hierarchy, applied in order of precedence:

  1. Managed settings — deployed by enterprise administrators, cannot be overridden
  2. User settings (~/.claude/settings.json) — your personal defaults across all projects
  3. Project settings (.claude/settings.json) — committed to version control, shared with the team
  4. Local settings (.claude/settings.local.json) — personal project overrides, not committed

The fields worth configuring in your project settings:

{
  "model": "sonnet",
  "effortLevel": "medium",
  "permissions": {
    "allow": [
      "Bash(git *)",
      "Bash(go test *)",
      "Bash(go build *)",
      "Bash(make *)"
    ],
    "deny": ["Bash(rm -rf *)", "Bash(git push --force *)"]
  },
  "autoMemoryEnabled": false,
  "outputStyle": "concise"
}

The allow list lets Claude execute those commands without asking for permission every time. The deny list blocks them entirely — even if you explicitly ask. For a Go project, allowing go test, go build, and make commands makes sessions flow without constant interruption. Blocking destructive git and shell operations is a safety net worth having, especially in sessions that run long.

The defaultMode setting changes the default permission posture:

{
  "permissions": {
    "defaultMode": "plan"
  }
}

With defaultMode: "plan", every session starts in Plan Mode. Claude reads and analyzes — never writes — until you explicitly approve its proposed plan. For unfamiliar codebases, high-stakes changes, or any situation where you want a review step before modification, this is a sound default. You can switch modes mid-session with Shift+Tab.

Subagents and Skills

When a task inside your session needs focused, isolated work — auditing a security module, running a deep research session on an unfamiliar codebase section, executing a batch migration — delegating to a subagent keeps your main session clean. The subagent runs in its own context. Your main session doesn’t fill up with work that belongs somewhere else.

Claude Code includes four built-in subagent types:

  • Explore — read-only tools, optimized for codebase research
  • Plan — produces plans without making changes
  • Edit — the full coding agent with read and write access
  • general-purpose — default balance of tools and permissions

Custom subagents live in .claude/agents/ and become available to Claude automatically. A code reviewer subagent for a Go project looks like this:

---
name: code-reviewer
description: Reviews code changes for security, performance, and correctness issues
model: opus
allowed-tools: Read, Grep, Glob
---

You are a senior Go code reviewer. When reviewing code, focus on:

1. Security vulnerabilities — SQL injection, improper input validation, secrets in code
2. Performance issues — N+1 database queries, missing indexes, unnecessary allocations
3. Error handling — unchecked errors, improper error wrapping, missing context
4. Go idioms — whether the code follows effective Go patterns

Do not suggest cosmetic refactors unless they address a real issue.

Commit this to version control and the entire team gets the same reviewer behavior.

Skills are the complement to subagents. Where a subagent is an isolated agent with its own context, a skill is a reusable prompt — a playbook or procedure — that runs in your current session. Skills live in .claude/skills/ and become available as /slash-commands.

A deploy skill that only you can trigger manually:

---
name: deploy
description: Deploy the application to staging
disable-model-invocation: true
allowed-tools: Bash(make *) Bash(git *)
---

Deploy to staging:

1. Run the full test suite: `make test`
2. Build the production binary: `make build`
3. Run `make deploy-staging`
4. Verify the health check at https://staging.example.com/health
5. Report the deployment status and any issues found.

The disable-model-invocation: true field prevents Claude from deciding to deploy because the code looks ready. That decision belongs to you — a slash command you invoke when you’re ready.

MCP: Connect Claude to Your World

MCP — the Model Context Protocol — is how you connect Claude Code to external systems. Databases, issue trackers, monitoring tools, design tools. Once an MCP server is connected, Claude can query it directly instead of you copying data into the chat.

Connecting a server takes one command:

# Connect GitHub for PR review and issue management
claude mcp add --transport http github https://api.githubcopilot.com/mcp/ \
  --header "Authorization: Bearer YOUR_GITHUB_PAT"

# Connect Sentry for production error analysis
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp

# Connect your PostgreSQL database (read-only connection)
claude mcp add --transport stdio db -- npx -y @bytebase/dbhub \
  --dsn "postgresql://readonly:pass@prod.db.com:5432/analytics"

# Connect Linear for issue tracking
claude mcp add --transport http linear https://mcp.linear.app/mcp

After connecting, workflows that used to require copying data into chat become direct conversations:

Implement the feature described in GitHub issue #342 and create a PR
What are the most common errors in the last 24 hours? Check Sentry.
Find customers who haven't made a purchase in 90 days

MCP servers have three scope levels. Local scope (the default) stores the configuration in your home directory — it loads only in the current project and stays private to you. Project scope stores configuration in .mcp.json at the project root, which you commit to version control so the whole team gets access. User scope makes a server available across all your projects.

For database connections with credentials, use local scope. For team-wide integrations like GitHub or Linear, use project scope and commit the .mcp.json. The credentials themselves stay out of version control — use environment variable expansion in the config file.

The tool search feature, enabled by default, defers MCP tool definitions until Claude actually needs them. Adding many MCP servers does not eat your context window at session start. Only the tools Claude actually invokes in a session consume context.

The Four Phases of a Good Session

The Claude Code best practices documentation describes a four-phase workflow. Teams that skip phases wonder why their sessions produce inconsistent results.

Explore first. Before writing a single line, have Claude read the relevant code. "Read the authentication module and tell me what you find." This phase costs almost nothing and saves significant time. Claude builds an internal model of the codebase that informs every subsequent decision. Running this in Plan Mode or with the Explore subagent keeps it read-only.

Plan before implementing. Use --permission-mode plan at startup, or press Shift+Tab to cycle into Plan Mode during a session. Have Claude propose an implementation. Review it. Push back on steps that conflict with codebase conventions or team patterns. When you accept the plan, Claude names the session from the plan content — you can find it in the session picker later.

Implement with focus. Execute the plan. If the implementation goes sideways mid-session, Ctrl+C stops Claude immediately. Redirect and continue. Use /clear between distinct tasks to prevent context from a finished task from polluting the next one.

Commit with the session context. Ask Claude to write the commit message — it has the context of what changed and why. "Create a PR for these changes" links the session to that PR. You can resume from it later with claude --from-pr 342. That linkage is useful when a reviewer asks questions and you need to return to the context that produced the change.

Each phase uses Claude’s capabilities differently. Exploration leverages read access and synthesis. Planning leverages reasoning depth. Implementation leverages code generation. Committing leverages the summary capability that knows what just happened.

Running Without You: Headless and CI

The -p flag (print mode) puts Claude Code into non-interactive mode. It reads the prompt, runs the task, prints the result, and exits. This is the flag that makes Claude Code usable in CI/CD pipelines, scheduled tasks, and shell scripting.

# Use as a code reviewer in CI
claude -p "Review the diff vs main and report issues. Format: filename:line | description"

# Pipe data through Claude
cat error.log | claude -p "Identify the root cause of this error" > analysis.txt

# Output structured JSON for downstream processing
claude -p "Audit this codebase for security vulnerabilities" --output-format json > report.json

The --output-format flag accepts text (default), json (full conversation metadata), and stream-json (real-time JSON objects as Claude works). Use json when you need to process Claude’s output programmatically. Use stream-json when you need to react to results as they come rather than waiting for the full session to finish.

In GitHub Actions:

- name: Claude Security Review
  run: |
    claude -p "Review changes in this PR for security vulnerabilities.
    Report specific file locations and severity." \
      --output-format text
  env:
    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

The headless mode also enables the fan-out pattern: running multiple Claude instances in parallel, each in an isolated Git worktree.

# Four parallel tasks, four isolated branches
claude --worktree feature-auth -p "Implement the OAuth2 middleware" &
claude --worktree fix-billing -p "Fix subscription billing bug #412" &
claude --worktree tests-api -p "Write integration tests for the orders API" &
wait

Each --worktree creates an isolated branch and working directory. Changes don’t collide. When a task finishes, you review and merge. The worktrees are cleaned up automatically if there are no changes, or you can keep them to inspect the work.

Agent Teams: Coordinated Parallel Work

Agent Teams is an experimental feature — enable it with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1. The model differs from subagents in an important way: instead of a main agent that delegates isolated tasks to workers, you get a lead agent and a set of teammates who coordinate through a shared task list and mailbox.

Subagents are the right tool for isolated work with a clear start and end — “audit this module,” “write tests for this service,” “generate the migration.” Agent Teams are for complex work that requires ongoing coordination — multiple agents working on different parts of the same feature, sharing findings and unblocking each other as they go.

The recommended team size is 3-5 teammates. Beyond that, coordination overhead degrades the work. The lead distributes tasks through the shared task list. Teammates claim tasks, complete them, and post results back. When a teammate is blocked, it posts to the mailbox and the lead can reassign or provide context.

For most projects, subagents with worktree isolation cover the parallel work case without the experimental complexity. Agent Teams become worth the overhead on projects large enough that a single session genuinely cannot hold the necessary context — think full-stack features that touch mobile, backend, and infrastructure simultaneously.

Token Efficiency in Practice

The fastest way to degrade a Claude Code session is to let context accumulate without intention. A session running for two hours that has changed focus three times, has hundreds of tool results, and has read dozens of files is expensive and increasingly unreliable.

Three practices that make a measurable difference:

Use /clear between tasks. Switching from fixing a bug to adding a feature? Clear the context. The bug is done. Its full history — the files read, the tests run, the failed attempts — is not useful for the feature you’re starting. Clear, and start fresh with only the CLAUDE.md loaded.

Use /compact proactively. Don’t wait for the session to get confused before compacting. Compact after a major phase completes — after the exploration phase, after the implementation is done but before you start reviewing. The summary you get from a deliberate compact is better than the compaction that happens when the window is nearly full.

Use subagents for investigation. When you need to understand a large module before modifying it, run the exploration in a subagent. The subagent gets its own context. Your main session doesn’t fill up with thousands of tokens of read-only file contents that are only useful for that one research step.

The numbers matter here. A tool result that returns a 500-line file uses roughly the same context as 10 follow-up messages. If you’re reading many large files for research, that context never gets recovered — it compresses in the summary, but you can’t query it the same way. Using the Explore subagent for research phases is not a workaround; it’s the intended pattern.

The Sessions You’ll Return To

Claude Code saves every session automatically. All of them are resumable. Most developers discover this feature late — and wish they had been naming their sessions from the start.

# Name a session at startup
claude -n auth-refactor

# Or rename during a session
/rename auth-refactor

# Resume by name later
claude --resume auth-refactor

When you create a PR with gh pr create, the session links to that PR automatically. Return to the exact context that produced the changes with claude --from-pr 342. When a reviewer asks why a decision was made three days later, you can resume the session, read the exploration notes, and answer with actual context rather than reconstructed memory.

The /resume command (without arguments) opens an interactive picker. Press Space to preview a session before resuming. Press Ctrl+R to rename a session from the picker. Filter by branch with Ctrl+B to find sessions related to your current work.

Long-running sessions that become large enough to re-read at substantial cost will offer a “resume from summary” option. This is useful for returning to a session from a previous week — you get the essential context without reloading the full history.


The best developers don’t use Claude Code as a faster keyboard. They use it as a collaborator who never forgets the codebase and never gets tired of reading one more file.